Nested model (attributes)とは
Railsの超便利機能で、親と子の関係もしくはhas one
関係をnested
と指定することで、
親を作成時に同時に子も作成してしまうことができる。
https://github.com/plataformatec/simple_form/wiki/Nested-Models
指定するためには下記のようにする。
class Parent < ApplicationRecord
has_many :children
accepts_nested_attributes_for :children
end
class Child < ApplicationRecord
belongs_to :parent
end
Nested attributesでのモデル作成が失敗してしまう場合
例えば、parent
を作成するフォームでnestedされたchild
を一緒に作成することを考える。
フォームは下記のようになる。
<%= simple_form_for @parent, :html => { :class => 'form-horizontal' } do |f| %>
<%= f.input :name %>
<%= f.simple_fields_for :children, @parent.children.build do |c| %>
<%= c.input :name %>
<% end %>
<%= f.button :submit, :class => 'btn-primary' %>
<%= link_to t('.cancel', :default => t("helpers.links.cancel")),
parents_path, :class => 'btn btn-default' %>
<% end %>
しかし、このフォームで更新ボタンを押すと、Children parent must exist
とエラーを出してトランザクションがロールバックしてしまう。
理由と解決
処理中、Children
を作成するときに、parent_id
が必要だと主張する。
でもParent
も今作成中なわけなので、DBに登録して初めて得られるIDは持っていない。
ここで、Parent
とChildren
の意見が相反してエラーが発生しトランザクションがロールバックする。
Rails 5.0ではこれを回避するための方法として、inverse_of
が導入されており、
親子両方のモデルにinverse_of
を設定することで、id違反を解消してくれる。
http://stackoverflow.com/questions/39090576/rails-5-error-message-child-model-parent-model-must-exist
class Parent < ApplicationRecord
has_many :children, inverse_of: :parent
accepts_nested_attributes_for :children
end
class Child < ApplicationRecord
belongs_to :parent, inverse_of: :children
end
Railsアプリサンプル
下記に置きました。Parent
->child
->descendants
の3階層でのnestedを実現しようとして、
descendantsをちゃんと実装する前に力尽きました。でも、しています。parent
->child
のnestedの更新は成功