In Rails, scopes provide a shortcut your models’ most frequently used queries.
For instance, on a Widgets model, you might have a scope called available, which runs Widgets.where(“quantity_in_stock > 0”).
1 2 3 |
# app/models/widget.rb scope :available, -> { where("quantity_in_stock > 0") } |
You can achieve the same effect with a class method on the Widgets model.
1 2 3 4 5 |
# app/models/widget.rb def self.available where("quantity_in_stock > 0") end |
In either case, Widget.available returns an ActiveRecord relation with the matching records, just as if you had called the where method directly.
1 2 3 |
# some model or controller or view Widget.available # returns an ActiveRecord relation with available widgets |
If class methods and scopes do the same thing, why would you use one over the other?
Scopes, it turns out, are less error-prone.
To find out why, we need to examine a more complex query.
Say that widgets have a discontinuation_date. Once a widget hits that date, it is no longer available.
We’ll expand our available scope/method to take the discontinuation_date into account.
1 2 3 |
# app/models/widget.rb scope :available, -> on { where("quantity_in_stock > 0 AND discontinuation_date > ?", on) if on.present? } |
Here, we show widgets that are currently available and haven’t hit their discontinuation date.
1 2 3 4 5 6 |
# app/models/widget.rb def self.available(on) where("quantity_in_stock > 0 AND discontinuation_date > ?", on) if on.present? end |
Now, say you called Widget.available(nil).order(“title”).
The class method returns a nil object, and you receive an error stating that there is no method order on a nil object. Not good!
The scope, on the other hand, returns a blank ActiveRecord relation. Running order on a blank ActiveRecord relation returns that same relation. No error. Good!
Choose scopes over class methods in your models.
Scopes avoid the problem of nil objects, which make code messy and error-prone.
Scopes don’t return the dreaded nil objects, instead returning a blank relation on which you can run any ActiveRecord method. You could say they implement the null object pattern.
The most direct and bullet-proof way to avoid nil object errors is to avoid nil objects
– If You Gaze Into Nil, Nil Gazes Also Into You by thoughtbot
For more details on the differences between class methods and scopes, check out Active Record Scopes vs. Class Methods on Plataformatic’s blog.
Hired.com brings Rails job offers to you. Free for candidates. Salaries from $75,000 to $250,000. Sign up now!