Use Concerns in Rails
When it comes that you need to reuse some functions across different models in Rails, Concern comes to rescue.
In our example, we have a few stats models which all have result_on
field, which needs to be calculated from passed params (start_time and end_time).
In StatsExtentions
module, we define the calculation.
module StatsExtensions
extend ActiveSupport::Concern
def self.during(start_time = nil, end_time = nil)
if start_time.is_a?(Range)
end_time = start_time.max
start_time = start_time.min
else
start_time = -DateTime::Infinity.new if start_time.blank?
end_time = DateTime::Infinity.new if end_time.blank?
end
where(result_on: start_time..end_time)
end
end
end
In those models, we also have common fields that we do generic sql calculations on as well. For example, they all have bids
and total
columns. We need to get sum of those fields. So inside include do
block, we add:
def self.build_sum
select(
arel_table[:bids].sum.as('bids'),
arel_table[:total].sum.as('total'),
)
end
def self.sum_staticstis
build_sum.group_by_segment
end
The build_sum
function select all the fields that need to be sum on and sum_staticstis
group them differently based on the model definition. It allows each model has its own field structure and can still leverage the common summation function.
In one of our models, we need to include this module:
class AccountStat < ActiveRecord::Base
include StatsExtensions
scope :group_by_segment, -> { group(:account_id) }
end
group_by_segment
scope is what sum_statistics
references. This way we could call AccountStat.sum_statistics
, which would coalesce bids and total fields and group by account_id.