Overview
When generating data for a report, the common approach is to specify measures and dimensions in the YAML file, but if you want to use any Ruby logic to generate the data, you can do so with a data_method
.
To use a data_method
, create a class method that takes properties
as an argument and returns the data for the report:
# app/services/my_data_methods.rb
class MyDataMethods
# { 'Bernice' => 191, 'Carlee' => 160, 'Edison' => 60, ... }
def self.posts_by_author(properties)
Post.joins(:author).group('authors.name').order('authors.name').count
end
end
Then set data_method
to that class method in the report's YAML file:
data_method: MyDataMethods.posts_by_author
chart:
options:
legend:
display: false
scales:
xAxes:
- scaleLabel:
display: true
labelString: Posts
yAxes:
- scaleLabel:
display: true
labelString: Author
The properties
argument is a hash that contains data from the report's YAML file, form filter data, and context_params that were passed to render_report
.
To see examples of the format of the data that should be returned by a data_method
, see Data Methods > One Dimension and Data Methods > Two Dimensions.
To create the chart above, simply add the following YAML file and call render_report
in any view:
YAML
config/reports_kit/reports/data_methods.yml
data_method: MyDataMethods.posts_by_author chart: options: legend: display: false scales: xAxes: - scaleLabel: display: true labelString: Posts yAxes: - scaleLabel: display: true labelString: Author
Note: The "chart.options" option is passed to Chart.js, so any values supported by Chart.js are supported here, too.
View
app/views/my_controller/my_view.html.haml
= render_report 'data_methods'
Data Methods
app/services/my_data_methods.rb
class MyDataMethods # { 'Bernice' => 191, 'Carlee' => 160, 'Edison' => 60, ... } def self.posts_by_author(properties) Post.joins(:author).group('authors.name').order('authors.name').count end # [ # [["Jul 3, 2016", "Hilton"], 2], # [["Jul 10, 2016", "Hilton"], 2], # ... # [["Jul 3, 2016", "Carlee"], 3], # [["Jul 10, 2016", "Carlee"], 5], # ... # ] def self.posts_by_created_at_week_and_author(properties) # The `group_by_week` method is provided by the `groupdate` gem. Post.joins(:author).group_by_week('posts.created_at').group('authors.name').count.map do |(date, author_name), count| [[date.strftime('%b %-d, %Y'), author_name], count] end end # { 'Bernice' => 191, 'Carlee' => 160, 'Edison' => 60, ... } def self.posts_by_author_with_filters(properties) ui_filters = properties[:ui_filters] posts = Post.joins(:author).group('authors.name').order('authors.name') posts = posts.where(created_at: ReportsKit.parse_date_range(ui_filters[:created_at])) if ui_filters[:created_at].present? posts = posts.where(is_featured: true) if ui_filters[:is_featured] posts = posts.where(author_id: ui_filters[:author]) if ui_filters[:author].present? posts = posts.where('title ILIKE ?', "%#{ui_filters[:title]}%") if ui_filters[:title].present? posts.count end end
Model
app/models/post.rb
class Post < ApplicationRecord belongs_to :author has_many :post_views, dependent: :destroy has_many :posts_tags, dependent: :destroy has_many :tags, through: :posts_tags include ReportsKit::Model reports_kit do aggregation :average_time_to_publish, [:average, 'posts.published_at - posts.created_at'] contextual_filter :for_author, ->(relation, context_params) { relation.where(author_id: context_params[:author_id]) } dimension :approximate_views_count, group: 'ROUND(posts.views_count, -1)' filter :is_published, :boolean, conditions: ->(relation) { relation.where(status: 'published') } end STATUSES = %w(draft private published).freeze def to_s title end end
Model's Columns
id integer author_id integer title string status string published_at datetime is_featured boolean views_count integer created_at datetime updated_at datetime