Rails - order on column's values (priority column)

A simple CASE WHEN can do the trick (postgreSQL syntax used here):

scope :urgency_ordered {
  order(<<-SQL)
    CASE tasks.urgency 
    WHEN 'HIGH' THEN 'a' 
    WHEN 'MEDIUM' THEN 'b' 
    WHEN 'LOW' THEN 'c' 
    ELSE 'z' 
    END ASC, 
    id ASC
  SQL
}

Call it this way:

Task.urgency_ordered

If using Rails 4.1+, consider using Active Record enums (Release Notes and Documentation) for a DB agnostic solution:

class Task < ActiveRecord::Base
  enum priority: [ :high, :medium, :low ] 
  # Or enum priority: { high: 0, medium: 1, low: 2 }

  scope :priority_order, ->{ order(:priority) }
  scope :reverse_priority_order, ->{ order(priority: :desc) }
end

This will require a new integer column for the priority, and copying/moving the text data that you have to the new integer column, which could be done in a migration. then calling Task.priority_order should do the trick.


It is late but here my 2cents. (Rails 4.2.1)

If you use the solution directly like this:

class Task < ActiveRecord::Base
    enum priority: { high: 0, medium: 1, low: 2 }
    scope :priority_order, order(:priority)
end

You will get this error: The scope body needs to be callable.

You need to call the scope like this.

scope :priority_order, -> {
    order(:priority)
}

define it like Proc or Lambda.

Why, you may ask :)

It makes sure what you have in the block is used each time the scope is triggered.