今回は双方向の関連付けで使用されるオプション、inverse_of
についてまとめました。基本的にはinverse_of
オプションを指定せずとも双方向からデータを参照することができます。一方で少し複雑な条件下では明示的にinverse_of
オプションを記述する必要があるため注意しましょう。
双方向の関連付けとは
双方向の関連付け(アソシエーション)とは、2つのモデル間のリレーションを表す仕組みのことです。代表例としてはhas_many
とbelongs_to
が挙げられます。
例えば、筆者モデル(Auther)と本モデル(Book)が1対多の関係にあるとします。
# app/models/auther.rb
class Author < ApplicationRecord
has_many :books
end
# app/models/book.rb
class Book < ApplicationRecord
belongs_to :author
end
この関連付けにより、以下のように双方向からデータを参照することができます。
# 筆者に紐付く本のタイトルが取得できる
> a = Author.first
> a.books.first.title
=> 'キングダム'
# 本に紐付く筆者が取得できる
> b = Book.first
> b.auther.name
> '原泰久'
inverse_ofオプションとは
Active Recordが提供しているinverse_of
オプションとは、双方向の関連付け(アソシエーション)を明示的に宣言することができるオプションです。
inverse_of
オプションはhas_many
の後に記述します。
先ほどの筆者と本の関係性について再度見ていきます。
# app/models/auther.rb
class Author < ApplicationRecord
has_many :books
end
# app/models/book.rb
class Book < ApplicationRecord
belongs_to :author
end
上記ではinverse_of
オプションが省略されており、実際は以下のような記述になります。
# app/models/auther.rb
class Author < ApplicationRecord
has_many :books, inverse_of: 'auther'
end
# app/models/book.rb
class Book < ApplicationRecord
belongs_to :author
end
このようにinverse_of
オプションを省略しても、双方向からデータを参照することができる仕組みはRails4.1で導入されました。
inverse_ofオプションが必要な場面
先程の例では、双方向の関連付け(アソシエーション)にinverse_of
オプションを付与しなくても双方向からデータを参照することができると解説しました。
しかしinverse_of
オプションを記述し、明示的に双方向の関連付けを宣言しなければならない場面があります。
それは:through
や:foreign_key
オプション、カスタムスコープを使用している場合です。これらの場合はActiveRecordが双方向の関連付けを自動認識しません。
例えば、以下のようなモデルがあると仮定します。
# app/models/auther.rb
class Author < ApplicationRecord
has_many :books
end
# app/models/book.rb
class Book < ApplicationRecord
belongs_to :writer, class_name: 'Author', foreign_key: 'author_id'
end
この場合、ActiveRecordが双方向の関連付けを自動認識できないため、BookからAutherのデータを参照することができません。
# 筆者に紐付く本のタイトルが取得できる
> a = Author.first
> a.books.first.title
=> 'キングダム'
# 本に紐付く筆者が取得できる
> b = Book.first
> b.auther.name
> Traceback (most recent call last):
1: from (irb):4
NoMethodError (undefined method `name' for nil:NilClass)
BookからAutherのデータを参照したい場合は、以下のようにinverse_ofオプションを追加することで、双方向からのデータ参照を行うことができるようになります。
# app/models/auther.rb
class Author < ApplicationRecord
has_many :books, inverse_of: 'writer'
end
# app/models/book.rb
class Book < ApplicationRecord
belongs_to :writer, class_name: 'Author', foreign_key: 'author_id'
end
# 筆者に紐付く本のタイトルが取得できる
> a = Author.first
> a.books.first.title
=> 'キングダム'
# 本に紐付く筆者が取得できる
> b = Book.first
> b.auther.name
> '原泰久'
:through
や:foreign_key
オプション、カスタムスコープを使用している場合は、has_manyの関連付けを宣言する際にinverse_of
オプションを忘れずに付与するようにしましょう。
まとめ
inverse_of
とは双方向の関連付けを明示的に宣言することができるオプションinverse_of
オプションはhas_many
の後に宣言するinverse_of
を省略しても、双方向からデータを参照することができるような仕組みはRails4.1で導入された:through
や:foreign_key
オプション、カスタムスコープを使用している場合は、ActiveRecordが双方向の関連付けを自動認識しないため、明示的にinverse_of
オプションを宣言する必要がある
参考
今回は双方向の関連付けで使用されるオプション、inverse_of
についてまとめました。複雑な関連付けを使用している場合は、inverse_of
オプションを忘れずに指定するようにしましょう。