Shoken Startup Blog

KitchHike Founder/CTO

ActiveRecord4, Rails4のinverse_ofについて理解したメモ

MongoDB(mongoid)でも使える。

inverse_ofとは

inverse_ofを指定したリレーションのある2つのモデルでは、双方から同一のインスタンスを参照できるようになる。両者ともメモリ上で同一のインスタンスとして扱われる。
逆に、inverse_ofの設定が無いと同一として扱われず、一方からの変更がもう一方から参照しても変更されていない。

具体例

UserモデルとMenuモデルが1対多でリレーションしている状況を考える。Userが複数のMenuを登録できるWebサービスのイメージ。

f:id:sfujisak:20150714093037j:plain

ソースコード

class User < ActiveRecord::Base
  has_many :menus
end

class Menu < ActiveRecord::Base
  belongs_to :user
end

inverse_ofが無かったら

Userのフィールドnameの変更が、Menuからたどった場合に変更が参照できない。メモリ上で別インスタンスとして扱われているから。

user = User.first
menu = user.menus.first
user.name == menu.user.name # => true
user.name = "change"
user.name == menu.user.name # => false

inverse_ofを指定すると

class User < ActiveRecord::Base
  has_many :menus, inverse_of: :user
end

class Menu < ActiveRecord::Base
  belongs_to :user, inverse_of: :menus
end

メモリ上で同一インスタンスとして扱われるようになり、userもしくはuser.menuからnameを変更しても、常にuser.name == menu.user.nameがtrueを返すようになる。

ドキュメント

Active Record の関連付け (アソシエーション) | Rails ガイド

ActiveRecord::Associations::ClassMethods