MetaReports — A rails report engine
===================================================
Description
MetaReports is a Rails engine for reports. It provides a common metadata structure that can be exported in any desired format. If your report fits within the metadata convention you do not even need a template. However, it is very easy to create reports specific templates also.
MetaReports exports to HTML, PDF, and XLSX formats. More are to come.
Provides
- An ActiveRecord and other data models, a controller, and some generic views.
- Default views for all formats, that expect a title, subtitle, description, and one or more tables of data.
- Use css classes for easy styling
Philosophy
Templates / data structures only
There is a generator that installs templates only. Then you can use the data structures and templates in whatever way you see fit as you write your own controllers / reports.
Rails engine
The MetaReports engine is avowedly fat model. It is also ActiveRecord based. This could change if a better way makes sense.
- Fat model: All reports are class methods in the MetaReports::Report class. This allows one to generate reports in various contexts without creating an instance (e.g. a mailer.) The reports themselves are meant to be pure data without formatting, except for class names, and html cell content if that is needed.
- ActiveRecord: Right now a database record is required in addition to the class method. So far this is for convenience in listing available reports and handling permissions. Someday, the code for a report might also be stored in a database, or an abstract description of a report with a web based query builder could be implemented.
Thoughts on REST
The class names / html content may broken out into helpers or a decorator pattern or something else in the future. It is difficult to think of a useful generic way to specify HTML content (e.g. an HTML link within a paragraph of text) outside of the report method itself. A reports controller already breaks strict REST ideology (where does a report belong that combines 5 models?) and unnecessary work for an ideology does not help create a useful tool.
Usage
Installation
Add meta_reports your Gemfile:
gem 'meta_reports'
Run the bundle command to install it.
There are two ways to use MetaReports:
- Install the templates, partials, helpers, and models only. No ActiveRecord is used.
- Install and mount the engine. In addition to the above, you will have a controller, additional templates for creating forms, and an ActiveRecord model.
Install templates only
After installing the gem, run the generator:
rails generate meta_reports:install_templates
This copies over the meta_reports migration, model, views, and controller:
app/models/meta_reports/base.rb: The ActiveRecord base, should you need itapp/models/meta_reports/data.rb: The MetaReports::Data metadata model. Contains report data.app/models/meta_reports/table.rb: The MetaReports::Table model for storing options and table data.app/models/meta_reports/report.rb: The MetaReports::Report model for storing colors and, if you wish, report methods.app/helpers/meta_reports/reports_helper.rb: MetaReports helper methods.app/views/meta_reports/reports/templates/*: All templates.
Install the engine
After installing the gem, run the generator:
rails generate meta_reports:install_engine
This copies over the meta_reports migration, model, views, and controller:
db/migrate/<timestamp>_create_meta_reports_reports.rbapp/models/meta_reports/report.rbapp/controllers/meta_reports/reports_controller.rbapp/views/meta_reports/reports/*
Run the migration:
rake db:migrate
Add authentication/authorization to the reports controller if desired.
Writing a report
- With templates installed:
- Use the models and helper methods to create report data.
- Render it using the default templates, or any template of your own.
- With the engine installed:
- Write the data method using a static method in the
app/models/meta_reports/report.rbmodel. The method should accept the params hash as its single argument. It should return the data in the form of a MetaReports::Data object or a hash. - Create a new report record using the reports page. The name must match the data method name.
- If not using the default templates, write your own templates.
- Write the data method using a static method in the
MetaData
The key component of MetaReports is the metadata format. This allows you to write a data method once and export it to any supported format. If you follow convention, the default templates will work out of the box.
Data: A MetaReports::Data instance, which is a thinly wrapped hash. Returned by each report method. Methods:
- title: The report title.
- subtitle: The report subtitle, displayed just below the title.
- description: A description, usually displayed in paragraph form between the subtitle and tables of data.
- tables: A hash, where each key is the table title and the value is the data for each table (can be nil).
- template: Specify a template if you are not using the default template.
- page_orientation: :landscape or :portrait. Used on PDF and XLSX formats.
- page_margin: The page margin in pixels (72/inch), in single number or four value array format (top, right, bottom, left.) Used on PDF and XLSX formats. Specify XLSX header/footer margins by specifying a 5th and 6th value respectively.
- page_size: The page size. Used on the PDF format. See the Prawn documentation.
Table: A MetaReports::Table instance, which is a thinly wrapped two dimensional array of cells.
- options: The options for the whole table. If you are using a plain array, this hash must be the last item in the table.
- column_widths: Column widths hash, used only on Prawn PDF output.
- font_size: Font size for content. Used on PDF and XLSX output.
- group: Group the header and table together on one page. This will throw an error if it cannot be fit on one page.
- row_classes: A hash with keys specifying row number (0 first), and values being a string of classes.
- table_header: Defaults to true. First row in the table is a header row. Causes the row to be repeated on Prawn PDF tables if it breaks to another page.
Cell: A cell is either a single value, or a hash specifying options:
- content: The default content.
- html: Special content for the HTML report. Used to provide links and other markup.
- class: The class for this content. Used to specify color, alignment, style. For HTML, classes are directly added to the td tags and you are expected to provide appropriate CSS.
- left, center, right: A class of left/center/right or ending with such values will align the content. It is expected you will provide the HTML styles.
- bold, strong: A class of bold or strong will make the content bold.
- image: Specify an image. Only used on PDF output.
Examples
Here is a simple example. See the example class for more.
def self.moo(params)
MetaReports::Data.new do |d|
d.title = 'Le Moo'
d.subtitle = 'Ahem'
d.tables["The Big Moo"] = MetaReports::Table.new do |t|
t << ['Number', 'Title', 'Hey']
t << [1, 'Ode to Moo', 'Ow']
t << [2, 'Odious Moo', 'Eww']
t << [3, "#{params[:moo_type]} Moo", 'No Way!']
t << [3, 'Format', {content: "PDF/XLSX", html: "<span>HTML</span>", class: 'attention'}]
end
end
end
Colors
There is currently an incomplete implementation of shared colors. You will define your colors by name in the MetaReports::Report class in the COLORS hash constant. If a table row or cell contains a corresponding class name it will have that color in HTML and PDF. XLSX support is planned. It is also intended to implement a means of specifying cell text color.
Declaring Colors
Specify colors using the COLORS hash constnat in your MetaReports::Report class. An example COLORS hash is below:
COLORS = {
even: 'efefef',
odd: 'ffffff',
yellow: ['ffffaa', 'ffffcc', 'f9f9a4', 'f9f9c6'],
highlight: '$yellow_1 !important',
hover: ['ffcccc', 'ffc5c5']
}
Specifying colors for rows or cells
To specify a color for a cell, use a hash and specify the color name in the class:
table << [{content: "Colored cell", class: 'yellow'}]
To specify a color for a row, store the row's color in the table row_classes hash:
table.row_classes[row] = 'yellow'
Note the row number begins with zero, and excludes the header if enabled.
Inline CSS
MetaReports defaults to inline styling for HTML. If you wish to turn this off (and use either your own styles or the export below) set the following:
MetaReports::Base.inline_css = false
Export SCSS / CSS
When you run rake meta_reports:export_colors task it exports two SCSS files, one including HTML styles, the other including SCSS variables (for your use in other files.) The export uses the following conventions:
- The corresponding SASS variable will be named the same as the key (with $ prepended of course). If the value is an array, the variable names will be the class name plus a numerical suffix for each entry.
- The corresponding CSS entry will:
- be prefixed with 'tr.' to match table rows
- arrays of values will be converted into nth-child rules to color consecutive rows
Given the above example the generated lib/metareports_color_variables.scss SASS file will be:
$even: #efefef;
$odd: #ffffff;
$yellow_0: #ffffaa;
$yellow_1: #ffffcc;
$yellow_2: #f9f9a4;
$yellow_3: #f9f9c6;
$highlight: $_yellow_1;
$hover_0: #ffcccc;
$hover_1: #ffc5c5;
And the generated assets/stylesheets/lib/metareports_colors.scss SASS file would be:
@import 'metareports_color_variables.scss';
tr.even { background: $even; }
tr.odd { background: $odd; }
tr.yellow:nth-child(4n+0) { background: $yellow_0; }
tr.yellow:nth-child(4n+1) { background: $yellow_1; }
tr.yellow:nth-child(4n+2) { background: $yellow_2; }
tr.yellow:nth-child(4n+3) { background: $yellow_3; }
tr.highlight { background: $yellow_1 !important; }
tr.hover:nth-child(2n+0) { background: $hover_0; }
tr.hover:nth-child(2n+1) { background: $hover_1; }
Note that you can specify !important and it will be reproduced in the CSS style.
To export only the variables file, use the meta_reports:export_color_variables Rake task.
To export only the colors file, use the meta_reports:export_colors_only Rake task.
TODO
- Expand common colors to spreadsheets, and enable coloring of text / individual cells
- Charts based on table data
- More formats (e.g. csv, json, text)
- Direct to email / print (using IPP) / fax
- Improved metadata conventions
Changelog
- 0.0.5: (11/16/13) Simplify color handling, color individual cells
- 0.0.4: (10/7/13) Colors rake task
- 0.0.3: (10/7/13) Template/model/helper generator
- 0.0.2: (9/29/13) Relax rails requirement, better testing
- 0.0.1: (9/29/13) Initial release
Development
Fork the project on github, edit away, and pull.
Rspec, and generator testing
Authors, License and Stuff
Code by Noel Peden and released under MIT license.



