Skip to content

Rodrigo Urubatan – About Code

Helping ruby developers to use the best tools for each job so they can solve hard problems, with less bugs and have more free time.

Menu
  • Home
  • My last presentations
  • About
  • Privacy Policy
Menu

Beware of rails default_scope – it might come back to bite you

Posted on 2019-05-23 by Rodrigo Urubatan

One great thing that ActiveRecord provides is the ability to create named scopes that can be chained, can be used in element collections and do all sorts of cool things!

But one not so cool thing that sometimes appears to be useful, is the definition of the default_scope, that adds that criteria to all queries using that element.

Once upon a time, a couple of weeks ago, I had to implement a “hidden” list of objects, based on a flag in the database, the objects should not appear in the Rails application, and I thought I’ll just create a default_scope with a simple where(flag:0)

Then I tried to build a query a month later, in a different part of the app that had nothing to do with the UI to process some batch jobs, that needed to get all the objects in the list, not only the ones that were not hidden from the UI and spent two hours fighting AR to list everything.

Of course you can use use “unscoped” to solve that, but only the lost hours fighting a bug caused by me is already enough to make me not want to use default scope again.

And it will create lots of weird bugs depending on what you added to the default scope.

For example, you thought that adding a default order to the object was a good idea? think again!

class TestModel < ApplicationRecord
         default_scope { order('created_at desc') }
 end
 
TestModel.order('name asc')
#   TestModel Load (3.3ms)  SELECT  "test_models".* FROM "test_models" ORDER BY created_at desc, name asc LIMIT ?  [["LIMIT", 11]]

With this simple test we just verified the amount of possible bugs for a default_scope/order by.

It can also create problems with your relationships, as we’ll see bellow:

class AnotherTest < ApplicationRecord
   belongs_to :test_model
   default_scope( where(published: true) }
 end
class TestModel < ApplicationRecord
   has_many :another_tests
end
tm = TestModel.last
tm.another_tests
  # AnotherTest Load (0.7ms)  SELECT  "another_tests".* FROM "another_tests" WHERE "another_tests"."published" = ? AND "another_tests"."test_model_id" = ? LIMIT ?  [["published", 1], ["test_model_id", 1], ["LIMIT", 11]]

Seems to be what you are looking for, until you need to list all unpublished posts from that TestModel, you just think, ok, I’ll use unscoped for it, right? Not so fast!

tm.another_tests.unscoped
#   AnotherTest Load (0.8ms)  SELECT  "another_tests".* FROM "another_tests" LIMIT ?  [["LIMIT", 11]]

“unscoped” will remove all current scopes, including association scopes.

It will also create problems if we use “dependents: :destroy” for example, because the scope will make rails delete only the published dependents, causing a possible “foreign key violation” in the database, causing the delete to fail.

So, in my opinion, except for some very rare orderings that will never change for your application, you should avoid “default_scope” with all your forces 😀

Related

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recent posts

  • Why Embrace Nesting in Ruby Modules?
  • An easy way to have a local “Github Copilot” for free
  • SPA without touching Javascript – The magic of Ruby on rails and Hotwire
  • I see Dead Jobs everywhere (sidekiq DeadSet)
  • Quick tips that help: rails notes

Arquives

  • May 2024
  • April 2024
  • February 2023
  • January 2023
  • December 2022
  • June 2021
  • March 2020
  • January 2020
  • July 2019
  • June 2019
  • May 2019
  • October 2018
  • September 2018
  • August 2018
  • July 2018
  • June 2018
  • May 2018
  • February 2018
  • January 2018
  • November 2017
  • August 2015
  • August 2014
  • July 2014
  • August 2007

Categories

  • AI
  • articles
  • cfp
  • firebase
  • gems
  • git
  • opinion
  • presentations
  • projects
  • rails6
  • ruby
  • Sem categoria
  • server-api
  • tutorials
  • Uncategorized
© 2025 Rodrigo Urubatan – About Code | Powered by Minimalist Blog WordPress Theme