Why using default_scope is a bad idea
default_scope is a method provided by ActiveRecord, which allows you to set
a default scope (as its name implies) for all operations done on a given model.
It can be useful for allowing soft-deletion in your models, by having a
deleted_on column on your model and setting the default scope to
class Animal default_scope where(deleted_on: nil) end
This will hide deleted records and only return non-deleted
ones in your queries after setting
deleted_on instead of
> Animal.limit(5) Animal Load (4.2ms) SELECT `animals`.* FROM `animals` WHERE `animals`.`deleted_on` IS NULL LIMIT 5
Quite useful! However,
default_scope has a dangerous behavior:
it affects your model’s initialization.
Say you were using STI on your
Animal model, and you had a
for always filtering your model by “Cat”:
class Animal default_scope where(type: "Cat") end
When you initialize a new Animal, it will always use the value defined in your default scope:
> Animal.new => #<Animal id: nil, created_at: nil, updated_at: nil, type: "Cat">
This can lead to some headaches when you’re not aware of this side-effect, and depending on the default scoped attribute/value it can cause some pretty bad bugs.
Also, I’d like to mention the fact that it’s very difficult to write queries
once you have used
default_scope on a model. For example:
Animal.where('deleted_on is not null') won’t work, you’d need to use
Animal.unscoped, which makes everything awkward. You also need to use
unscoped carefully, because it will remove all scopes of the relation, not just
the default scope.
I recommend that you always avoid default scope if possible. Prefer explicit scopes instead. If you really need to use it, use it with care.