order
order(*args)Applies an ORDER BY clause to a query.
#order accepts arguments in one of several formats.
symbols
The symbol represents the name of the column you want to order the results by.
User.order(:name) # SELECT "users".* FROM "users" ORDER BY "users"."name" ASC
By default, the order is ascending. If you want descending order, you can map the column name symbol to :desc.
User.order(email: :desc) # SELECT "users".* FROM "users" ORDER BY "users"."email" DESC
Multiple columns can be passed this way, and they will be applied in the order specified.
User.order(:name, email: :desc) # SELECT "users".* FROM "users" ORDER BY "users"."name" ASC, "users"."email" DESC
strings
Strings are passed directly to the database, allowing you to specify simple SQL expressions.
This could be a source of SQL injection, so only strings composed of plain column names and simple function(column_name) expressions with optional ASC/DESC modifiers are allowed.
User.order('name') # SELECT "users".* FROM "users" ORDER BY name User.order('name DESC') # SELECT "users".* FROM "users" ORDER BY name DESC User.order('name DESC, email') # SELECT "users".* FROM "users" ORDER BY name DESC, email
Arel
If you need to pass in complicated expressions that you have verified are safe for the database, you can use Arel.
User.order(Arel.sql('end_date - start_date')) # SELECT "users".* FROM "users" ORDER BY end_date - start_date
Custom query syntax, like JSON columns for PostgreSQL, is supported in this way.
User.order(Arel.sql("payload->>'kind'")) # SELECT "users".* FROM "users" ORDER BY payload->>'kind'
7Notes
Reorder
If you want to override previously set order (even through default_scope), use reorder() instead.
E.g.
User.order('id ASC').reorder('name DESC')
would ignore ordering by id completely
Ordering on associations
For ordering on the attribute of an associated model you have to include it:
Package.includes(:package_size).order("package_sizes.sort_order")
using hash as order
order can be specified as a hash, e.g.:
order(id: :desc)
This will prevent "ambiguous column" errors when the order is used with joins or includes.
Ordering on associations using merge
For ordering on the attribute of an associated model you can add joins to query and merge order scope: Product.joins(:category).merge(Category.order(priority: :desc))
reorder
adding to stevo's comment that reorder is also usefull when you have default scope in your model. eg: default_scope -> { order(created_at: :desc) }
arel_table order by
More objected way how to achieve ORDOR BY .... DESC is like this :
class User < ActiveRecord::Base
has_many :status_changes
def latest_status_change
status_changes
.order(StatusChange.arel_table['created_at'].desc)
.first
end
end
class StatusChange < ActiverRecord::Base
belongs_to :user
end
resulting in:
SELECT "status_changes".* FROM "status_changes" WHERE "status_changes"."user_id" = 1 ORDER BY "status_changes"."created_at" DESC
Benefits:
- you are strictly bound to Modelclass name => renaming table in model will not break the sql code (of if it will, it will explicitly break the syntax on Ruby level, not DB level)
- you still have the benefit of explicitly saying what table.column the order should be
- easier to re-factor parts to Query Objects
Careful with arel column
I use what @equivalent suggests a lot but be careful, you MUST state the direction otherwise methods like take/last/first will fail silently!
StatusChange.arel_table['created_at']. asc
not:
StatusChange.arel_table['created_at']