Edited at

Rails5の自己結合でハマる

More than 1 year has passed since last update.


tl;dr

Rails5を利用している環境で、1対多の自己結合を実現させるために以下のようなコードを書いた。

class Hoge < ApplicationRecord

has_many :children, class_name: 'Hoge', foreign_key: 'parent_id', dependent: :destroy
belongs_to :parent, class_name: 'Hoge'
end

何度DBにレコードを登録しようとしても、毎回以下のようなエラーが発生して登録できない。

ActiveRecord::RecordInvalid: バリデーションに失敗しました: Parentを入力してください

いや、親に当たるレコードは、parent_id持たないんだよなぁ。。。ってことで盛大にハマったのでメモ。


原因

参考にしたサイトの情報が古い(Rails4以前のもの)ばかりだったので、Rails5からの仕様変更でハマっていた。

Rails5からはbelongs_toアソシエーションは、デフォルトでrequire: trueになったので、nullでの登録ができなくなっていた。

※確かに、belongs_toなのに、id設定しないとかレアパターンなので、デフォルトをそっちにするのは自然なんだけど。

逆に、これまで通り(Rails4みたいに)belongs_toのアソシエーションでnullを許容したい場合は、optional: true使えばエラーは発生しなくなる。

class Hoge < ApplicationRecord

has_many :children, class_name: 'Hoge', foreign_key: 'parent_id', dependent: :destroy
belongs_to :parent, class_name: 'Hoge', optional: true
end