ActiveRecordで同じクラスに自動でinverse_ofが設定されたときの挙動がおかしい

unasuke.rb という会で2時間ほど OSS とかの作業をやる機会があったので、前から少し気になっていた件を調査して https://github.com/rails/rails/issues/35204 に Issue を出してみました。

inverse_of

ActiveRecord で hasmany や belongsto などを利用すると、特定の条件下では inverseof が自動で設定され、例えば user.posts.first.user のように子の親を辿ったときに同じオブジェクトが再利用されるという仕組みがあります。Post#user が呼ばれたときに SELECT * FROM users where userid = ? という不要な SQL が発行されず、ActiveRecord のオブジェクトが再利用されるという感じです。

しかし、同じクラスに対して自動で inverseof が設定され得る belongsto が複数個定義されていたとき、どうやら挙動がおかしく、一方の belongsto の inversion が他方の belongsto に影響を与えてしまうような感じになっていました。

考えている解決方法

inverseof を自動で設定させないオプションを渡すことで回避することもできますが、そもそもそういう inversion が自動で設定されてしまうこと自体がおかしいので、内部的に foreignkey ごとに inversion を管理するようにするか、あるいはそういう実装には上手くできないとしても、既に同じクラスに対して自動で inversion が定義されていたら2件目以降は自動で設定しないようにしたいなと考えています。