概要
Railsで多対多モデルのリレーションを貼る際にハマったことを記載しておきます。
環境
- Ruby 2.5.1
- Rails 5.2.3
モデル
下記のようなモデルを作るとします。
+------------+
+------------+ | PostTag |
| Post | +------------+ +------------+
+------------+ 1 * | id | | Tag |
| id |--------| post_id | * 1 +------------+
| content | | tag_id |--------| id |
+------------+ +------------+ | name |
+------------+
ハマった内容
通常はPostからTag(その逆も)を参照できるように以下のようなリレーションを定義すると思います。
class Post < ApplicationRecord
has_many :post_tags
has_many :tags, through: :post_tags
end
class PostTag < ApplicationRecord
belongs_to :post
belongs_to :tag
end
class Tag < ApplicationRecord
has_many :post_tags
has_many :posts, through: :post_tags
end
この際、上記のような記述順ではうまくいきますが、Postモデル、Tagモデルのhas_many
の順番が逆の場合は、上記の環境ではうまくいきませんでした。
class Post < ApplicationRecord
has_many :tags, through: :post_tags
has_many :post_tags
end
多対多で検索すると下記のような順番で記述している例もたくさんあるのですが、Rails5になって厳しくなったんでしょうかね。
ActiveRecord::HasManyThroughOrderError
エラーが出てしまうようです。
[1] pry(main)> Post.find(1).tags
Post Load (0.4ms) SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = 1 LIMIT 1
ActiveRecord::HasManyThroughOrderError: Cannot have a has_many :through association 'Post#tags' which goes through 'Post#post_tags' before the through association is defined.
from /mnt/e/Development/gunplus/vendor/bundle/ruby/2.5.0/gems/activerecord-5.2.3/lib/active_record/reflection.rb:943:in `check_validity!'