Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Railsのdefault_scopeは使うな、絶対(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。


  • 2017/10/31: 初版公開
  • 2021/11/04: 更新

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を使ってもよさそうな場面はありますか?

どうかこればかりは私を信じてください。使えばきっと痛い目にあいます。

関連記事

よくある?Rails失敗談 default_scope編

論理削除用paranoia gemがあるRailsプロジェクトで物理削除する方法


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。