ActiveRecord Rails 3 scope vs class method
There was more of a difference in Rails 2.x, since named_scopes did not execute your queries (so you could chain them), whereas class methods generally did execute the queries (so you could not chain them), unless you manually wrapped your query in a scoped(...)
call.
In Rails 3, everything returns an ActiveRecord::Relation
until you need the actual results, so scopes can be chained against class methods and vice versa (as long as the class methods return ActiveRecord::Relation
objects, not some other object type (like a count)).
Generally, I use scope
entries for simple one-liners to filter down my result set. However, if I'm doing anything complicated in a "scope" which may require detailed logic, lambdas, multiple lines, etc., I prefer to use a class method. And as you caught, if I need to return counts or anything like that, I use a class method.
As Dylan alluded to in his answer, one difference between scope and class method is that scopes are evaluated when the class is loaded. This may lead to unexpected result.
For example,
class Post < ActiveRecord::Base
scope :published_earlier, where('published_at < ?', Date.today)
end
is prone to error. The correct way is to use a lambda
class Post < ActiveRecord::Base
scope :published_earlier, -> { where('published_at < ?', Date.today) }
end
Lambda block is lazily evaluated. So Date.today is run when you call the scope, not when the class is evaluated.
If you use a class method, then you don't need to use lambda.
class Post < ActiveRecord::Base
def self.published_earlier
where('published_at < ?', Date.today)
end
end
Because with class method, the code is run at the time of method call.