Simple Scope Methods and Tricksy Scope Methods

Zoe Friedman
3 min readApr 3, 2021

Active Record class-level scopes methods are reusable custom queries that live inside your models. They are chain-able and give you ActiveRecord::Relation objects.

Redundantly, scope methods utilize the scope method which takes in two arguments: 1) the name you will use to call it and 2) a lambda, shown here as an active record query:

Side quest: What is a lambda? A lambda is a way of defining a block and parameters. Here are two very simple versions, one with an argument and one without:

sweet_lambda -> {puts "Peep this sweet Lambda"}times_three -> (x) { x * 3}

Now back to our scope method!

class Barfly < ApplicationRecord

scope :cant_drink -> { where("age < 21")}
...end

So when you’re in your Barfly controller, you will be able to do this:

class BarFlyController < ApplicationController

def index
@punkkid = Barfly.cant_drink.last
end
...end

You’ve chained “.last” onto your custom scope method! Allowing you to pull all Bar Flies whose ages are under twenty-one and extract the last one.

The above example is VERY simple. So here are the complex relationships I dealt with recently in a project that had me stumped:

One functionality I was determined to have in this project was the ability to sort all of the musician’s unique songs by the date of the gig AND it needed to filter out old gigs.

Very tricksy indeed.
Class GigSongsController < ApplicationController  def index    @array = current_musician.gig_songs.by_date.unique.not_over  endend

Above I have chained the following THREE scope methods:

class GigSong < ApplicationRecord...scope :by_date, -> { order(date: :asc) }scope :unique, -> { group(:song_id) }scope :not_over, -> { where("date > ?", DateTime.now)}...end

I even used the “by_date” scope method in other actions! See? — reusable! And if the “not_over” method has you scratching your head, remember, the 2nd argument will replace the question mark via SQL. You could even make that a variable to make it more dynamic!

scope :after_specific_date, -> (x) { where("date > ?", x)}

Here is another example that I scoured the internet for an example of, but to no avail. Let’s say you wanted to figure out which has the most of something. In my case, I needed to count all gigs via band and return the band with the most gigs. I did not figure this one out of my own. I must credit a queen, Ronnie Boniface, who helped me with this one:

class MusiciansController < ApplicationController...  def stats
@busiest = current_musician.bands.most_gigs.first
@busiest_count = @busiest.gigs.size
end
...end

Ultimately, this scope method belonged in my band model as I would be calling it on band objects:

class Band < ApplicationRecord...scope :most_gigs, -> { order(:gigs.length) }end

Not only was I puttsing around in the wrong class, but I didn’t realize that I could call upon methods WITHIN the query 🤯 See above that we’ve ordered the bands by the length of their gigs!

Hope this helps someone somewhere!

--

--