Railsのdefault_scopeは使うな、絶対(翻訳)
あるモデル全体にスコープを適用したい場合、default_scopeが利用できます。詳しくはRailsガイド: Active Recordクエリインターフェイス 14.スコープ(日本語)かRails APIドキュメントをご覧ください。
投稿を非表示にできる機能を持つブログシステムを書き始めるときを考えてみます。
次のように書かないこと
default_scopeを使う:
# app/models/post.rb
class Post < ActiveRecord::Base
default_scope { where(hidden: false) }
end
次のように書くこと
明示的にスコープを指定する:
# app/models/post.rb
class Post < ActiveRecord::Base
scope, :published -> { where(hidden: false) }
end
これで次のように書けます。
Post.published
default_scopeを使うべきでない理由
理由は2つあります。どちらも後になってコードが混乱したりバグつぶしに明け暮れたりすることを避けるのが目的です。
default_scopeを追加すると、モデルの初期化が影響を受けます。上の例で言うと、開発者が期待するかどうかにかかわらずPost.newするとデフォルトでhidden = falseになってしまいます。
いったん定義されたdefault_scopeを使わないようにするのはつらい作業です。default_scopeが不要な場面で削除するには、unscopedしたスコープ(!)を使わなければならず、しかも適用されていた関連付けなどの条件はすべて削除されてしまいます。
例: Post.first.comments.unscopedとすると、Postの最初のコメントだけではなく、データベース内のすべてのコメントを返します。
default_scopeよりも明快な解決法は、名前付きスコープを明示的に使うことです。default_scopeを使えばバグつぶしに何時間も費やすことになるでしょう。default_scopeは使わないでください。
default_scopeを使ってもよさそうな場面はありますか?
どうかこればかりは私を信じてください。使えばきっと痛い目にあいます。
概要
原著者の許諾を得て翻訳・公開いたします。