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の更新は成功