Simplify ActiveRecord Aggregates and Other Goodies via named_scope
We’ve been huge fans of named_scope since its introduction in Rails 2.1. If you are new to the named_scope concept, please read Ryan Daigle’s intro to named_scope and watch Ryan Bates’ named_scope RailsCast. Ryan Daigle also had a good follow up article explaining his utility scope gem.
With a recent project, we really started utilizing extensions with named_scope which is very powerful and cleaned up our code considerably.
For example, let’s say you have an issue tracking system that has an Entry model that belongs_to both a User model and a Project model. Using named_scope, we can easily access Entries for a date range filtered to both the Project and User level using named_scope lambdas:
To find the Entries for the last week for the first user, we would simply do:
u = User.first
u.entries.by_date(1.week.ago, Time.now)
To find the Entries for the last week for the first project, we would simply do:
p = Project.first
p.entries.by_date(1.week.ago, Time.now)
What happens if we want to see the sum of hours worked for a date range? This is where extensions come in very handy. Let’s add a “total_duration” extension to our named_scope:
Now to get the duration for the past week for the first user we simply do:
u = User.first
u.entries.by_date(1.week.ago, Time.now).total_duration
with similar logic at the project level.
To group all of the entries by project, we would do:
If you need the lambda arguments inside your named_scope extension, you will need to use “self.proxy_options”. For example, let’s say you need the from and to dates in order to calculate the average duration per weekday. That code would look something like this:
In the above example, “weekday_count” is a custom method we created to calculate the number of weekdays between 2 given dates.
The opportunities to simplify code using named_scope is great. As I was writing this post, one of our team members, Jason Derrett, created a named_scope to wrap a Xapian full text search into a Lesson model:
In this example, using Xapian to search for a keyword becomes as simple as:
Lesson.find_with_xapian "fishing"
How cool is that?!?
Are there any other cool named_scope tricks out there that any of you are using?