Home > Net >  Rails: sort collection with scope using one of two dates
Rails: sort collection with scope using one of two dates

Time:11-22

I'm trying to write a scope that sorts on one of two columns--if the first (scheduled_at) has data in it then use that data, otherwise resort to created_at.

def self.by_scheduled_at
  if scheduled_at
    order(scheduled_at: :desc)
  else
    order(created_at: :desc) 
  end  
end

This code fails because scheduled_at is an instance attribute and this is a class method.

How can I write this scope so it sorts the collection based on whether scheduled_at is present?

CodePudding user response:

I'm going to assume you mean to sort by whether created_at or sorted_at is present in each row. That is if sorted_at has a value, use that. But if it's nil, use created_at.

sorted_at created_at
2020-01-01 2030-01-01
null 2020-02-02
2020-03-03 null
2020-04-04 1999-01-01

For that you'd use coalesce; it returns the first non-null value. Then write it as a scope.

scope :by_scheduled_at, -> { order("coalesce(scheduled_at, created_at) DESC") }

CodePudding user response:

If you want a chainable scope, something like this should work (tested on MySQL, via the mysql2 gem):

scope :by_scheduled_at, -> { order(Arel.sql("IFNULL(scheduled_at, created_at) DESC")) } 

As noted by @Schwern, IFNULL is MySQL specific, use COALESCE for standard SQL (implemented also by SQLite and PostgreSQL).

  • Related