Rails
scope
default_scope

default_scopeにハマった

環境

  • Rails 5.0.3
  • ruby 2.3.3p222 (2016-11-21 revision 56859) [x86_64-darwin17]

事情

default_scopeにハマってしまったので、メモします。

UserとGroupのモデルがあって、UserはGroupの作成者として紐付いています。

user.rb
class User < ApplicationRecord
  has_many :groups 
  default_scope { where(is_deleted: false) }
end
group.rb
class Group < ApplicationRecord
  belongs_to :user
end

さて、GroupsControllerのindexにすべてのグループとその作成者の情報を表示するために、こういうコードを書きました。

groups_controller.rb
def index
   @groups = Group.includes(:user).all
end
<% @groups.each do |group| %>
  <tr>
    <td><%= group.id %></td>
    <td><%= group.name %></td>
    <td><%= group.user.name %></td>
    ...
  </tr>
<% end %>

そして、一つのユーザーを削除されました。そしたら、グループ一覧ページに以下のエラーになってしまった。

undefined method `name' for nil:NilClass

確かに、ユーザーが削除されたので、default_scopeが効いてuserが空っぽになっちゃう。

対策

いろんな方法を試したんだけど、Group.includes(:user).allこれを修正して、Groupの中からuserのdefault scopeを外すことができませんでした。

結局以下のあまりイケてない方法で解決しました。影響範囲は全Groupのユーザーになってしまった。

group.rb
belongs_to :user, -> { unscope(:where) }, inverse_of: :groups

inverse_ofはrubocopの警告で追加したんです。Groupモデルからuserのdefault scopeを外すようにしました。

感想

最初から手間を惜しまず、default_scopeを使わないのは正解でした!