San Francisco Museum of Modern Art

image by William Bout (unsplash RkJF2BMrLJc)

Only use named scopes outside models

Last time we discussed using the hash-style syntax in your #where methods but in my examples I did something I wouldn’t do in my real-life code…

RailsConf 2024

I'm co-chairing RailsConf 2024 in Detroit May 7–9. Come and join us 

Instead of…

…using #where scopes in your controllers or views.

class PostsController < ApplicationController
  def index
    @posts = Post.where(status: 'published')
  end
end

Use…

…only named scopes that you define in your model.

class Post < ApplicationRecord
  scope :published, -> { where(status: 'published') }
end

And then use them like so:

class PostsController < ApplicationController
  def index
    @posts = Post.published
  end
end

But why?

This technique improves the organisation of your code. It forces you to do two things that can really help keep you productive over time.

Firstly: naming the concepts you’re creating. When you name something aptly, you explain it, often for the benefit of “future you” or your colleagues.

Secondly: you have one place to look for all of this. If you define scopes outside your models you can end up with arbitrary scopes and conditions defined all over your code base. When you know where all the conditions are defined you’ll know where to look when you want to refactor or optimise database performance.

Why not?

For scopes involving #limit, simple #orders or pagination, there’s very little point in bothering to create specific scopes, as the syntax of the ActiveRelation methods are quite succinct.

Naming scopes is only beneficial when you gain extra clarity. Sometimes, with non-#where queries, there is no enhanced understanding from wrapping simple ActiveRelation methods inside a scope.

scope :by_title, -> { sort(:title) } # no benefit?
scope :by_updated_at, -> { sort(:updated_at) } # terrible name
scope :recently_updated, -> { sort(updated_at: :desc) } # probably worth doing

It’s worth bearing in mind that a named scope might still be a good choice for complex ordering or if the sorting is closely related to the conditions specified in a #where query.

A good heuristic to creating a named scope with ordering or limits is: can I easily name the concept? Is the result better than the existing ActiveRelation methods?

Brighton Ruby 2024

Still running UK’s friendliest, Ruby event on Friday 28th June. Ice cream + Ruby 


Last updated on March 4th, 2018 by @andycroll

An email newsletter, with one Ruby/Rails technique delivered with a ‘why?’ and a ‘how?’ every two weeks. It’s deliberately brief, focussed & opinionated.