inverse_of について


inverse_of とは

ActiveRecord で双方向の関連付けをしている以下のようなクラスがあるとする。

class Customer
  has_many :orders
end

class Order
  belongs_to :customer
end

同じ Customer を指しているのに
次のような変更を加えると
データの不整合が生じてしまう。

c = Customer.first
o = c.orders.first

c.first_name = "Change"

c.first_name == o.customer.first_name #=> false

これは、同じデータを持つ別々のオブジェクトであることが原因。

c = Customer.first
o = c.orders.first

c.equal? o.customer #=> false

inverse_of を使うと、同じオブジェクトをみるようになり、
このようなデータの不整合が生じなくなるとともに
無駄にオブジェクトを生成しないので、アプリケーションの効率もよくなる。

Q: いつも使えばいいのでは?

オプション指定する必要があるということは、inverse_of を使いたくないタイミングなんてのがあるのだろうかと疑問に思った。

A: Rails4.1 以降はデフォルト化されていた

結局、 inverse_of を使いたくないタイミングというのは見つけられず、
代わりに、 inverse_of は自動で設定されるようになったということがわかった。

この記事が一番わかりやすかった。
Automatic Inverse Associations に至るまでの経緯から その実現方法について簡単な説明付き。
http://wangjohn.github.io/activerecord/rails/associations/2013/08/14/automatic-inverse-of.html

上の記事によるとこのコミットで追加されている。
https://github.com/rails/rails/commit/26d19b4661f3d89a075b5f05d926c578ff0c730f

ただし、自動で inverse_of を設定してくれるのは
:has_many, :has_one, :belongs_to 関連付けに対してだけ。
:conditions, :through, :polymorphic, :foreign_key などを使用した複雑な名前付けが絡んでくると、set_automatic_inverse_of メソッドの扱える範囲を越えてしまう。