Reputation: 21
I have a Site model with relation Notification. The site has several notifications every day. I try to calculate the sum of notifications for a few days and want to sort the sites by this sum.
class Site
has_many :notifications
scope :sort_by_notifications_between_dates_asc, -> (start_date, end_date) { left_joins(:notifications).merge(Notification.between_dates(start_date, end_date)).order(Arel.sql("count(notifications.*) asc")) }
scope :sort_by_notifications_between_dates_desc, -> (start_date, end_date) { left_joins(:notifications).merge(Notification.between_dates(start_date, end_date)).order(Arel.sql("count(notifications.*) desc")) }
end
class Notification
belongs_to :site
scope :between_dates, -> (start_date, end_date) {where(self.arel_table[:created_at].gteq(start_date.at_beginning_of_day).and(self.arel_table[:created_at].lteq(end_date.at_end_of_day)))}
end
It is possible for ransack to create a scope for sorting, but I have not found a way to pass the arguments (start_date and end_date) to this scope.
= sort_link(@q, :notifications_between_dates, t('.notifications_between_dates'), default_order: :desc)
I do not need to filter sites by date. I need to sort the sites by the sum of the notifications for the period of time. Is this even possible?
Upvotes: 1
Views: 2232
Reputation: 21
I found half the solution. I created ransacker with arguments
ransacker :notifications_between_dates, args: [:parent, :ransacker_args] do |parent, args|
start_date, end_date = args
query = <<-SQL
COALESCE(
(SELECT COUNT(notifications.*)
FROM notifications
WHERE notifications.site_id = sites.id
AND notifications.created_at >= '#{start_date}'
AND notifications.created_at <= '#{end_date}'
GROUP BY notifications.site_id)
,0)
SQL
Arel.sql(query)
end
Then we can sort records in this way
q = Site.ransack(sorts: [{name: :notifications_between_dates,
dir: 'asc',
ransacker_args: [Time.now-20.days,Time.now]}])
But looks like sort_link helper does not support passing ransacker_args via GET request in s parameter.
Upvotes: 1