default_scope
This works for Rails 4+:
class Book < ActiveRecord::Base
default_scope { order(created_at: :desc) }
end
For Rails 2.3, 3, you need this instead:
default_scope order('created_at DESC')
For Rails 2.x:
default_scope :order => 'created_at DESC'
Where created_at
is the field you want the default sorting to be done on.
Note: ASC is the code to use for Ascending and DESC is for descending (desc
, NOT dsc
!).
scope
Once you're used to that you can also use scope
:
class Book < ActiveRecord::Base
scope :confirmed, :conditions => { :confirmed => true }
scope :published, :conditions => { :published => true }
end
For Rails 2 you need named_scope
.
:published
scope gives you Book.published
instead of
Book.find(:published => true)
.
Since Rails 3 you can 'chain' those methods together by concatenating them with periods between them, so with the above scopes you can now use Book.published.confirmed
.
With this method, the query is not actually executed until actual results are needed (lazy evaluation), so 7 scopes could be chained together but only resulting in 1 actual database query, to avoid performance problems from executing 7 separate queries.
You can use a passed in parameter such as a date or a user_id (something that will change at run-time and so will need that 'lazy evaluation', with a lambda, like this:
scope :recent_books, lambda
{ |since_when| where("created_at >= ?", since_when) }
# Note the `where` is making use of AREL syntax added in Rails 3.
Finally you can disable default scope with:
Book.with_exclusive_scope { find(:all) }
or even better:
Book.unscoped.all
which will disable any filter (conditions) or sort (order by).
Note that the first version works in Rails2+ whereas the second (unscoped) is only for Rails3+
So
... if you're thinking, hmm, so these are just like methods then..., yup, that's exactly what these scopes are!
They are like having def self.method_name ...code... end
but as always with ruby they are nice little syntactical shortcuts (or 'sugar') to make things easier for you!
In fact they are Class level methods as they operate on the 1 set of 'all' records.
Their format is changing however, with rails 4 there are deprecation warning when using #scope without passing a callable object. For example scope :red, where(color: 'red') should be changed to scope :red, -> { where(color: 'red') }
.
As a side note, when used incorrectly, default_scope can be misused/abused.
This is mainly about when it gets used for actions like where
's limiting (filtering) the default selection (a bad idea for a default) rather than just being used for ordering results.
For where
selections, just use the regular named scopes. and add that scope on in the query, e.g. Book.all.published
where published
is a named scope.
In conclusion, scopes are really great and help you to push things up into the model for a 'fat model thin controller' DRYer approach.