LoginSignup
1
0

More than 1 year has passed since last update.

【Rails6】cocoonによる動的フォーム作成時に注意すべき点。「"accepts_nested_attributes_for"」、「"can't be blank"」

Last updated at Posted at 2021-10-10

cocoonを用いて、動的に変化するフォームを作成した際にハマったことを記します。
cocoonの導入は以下の記事を参考にしました。
【Rails】cocoonを用いて親子孫関係のテーブルに複数のデータを同時保存する方法 - Qiita
【Rails6】cocoonを使った動的フォーム入力画面の作り方 - Qiita

問題概要

 以下のような3つのモデルを作成し、関連づけたと仮定します。

関係 モデル名
Parent
Child
Grandchild

上記記事を参考にしながらフォームを作成し、できたフォームよりデータを送信したら、以下のようなバリデーションに引っかかりました。

Child Grandchild child can't be blank Child Parent can't be blank

原因

各モデルのvalidationの記述に問題がありました。

parent.rb
has_many :children, dependent: :destroy
accepts_nested_attributes_for :children
child.rb
belongs_to :parent
has_many :grandchildren, dependent: :destroy
accepts_nested_attributes_for :grandchildren
validates :parent_id, presence: true
grandchild.rb
belongs_to :child
validates :child_id, presence: true

accepts_nested_attributes_forによって、親作成時にその子供のデータも同時に作成できるようになります。
このとき、childのparent_idやgrandchildのchild_idは各データの保存と同時に、そのデータのidが格納されます。
従って、データを保存し終わるまでは各フォームから、

_children_fields.html.erb
<%= hidden_field_tag :parent_id, @parent.id %>
_grandchildren_fields.html.erb
<%= hidden_field_tag :child_id, @child.id %>

のようにインスタンス変数から直接値を代入するよう試みても、各データは保存される前でありidを持たないため、バリデーションのpresenceに引っかかってしまいます。

解決策

方法は非常にシンプルで、validates :child_id, presence: truevalidates :parent_id, presence: trueを削除します。

おわりに

accepts_nested_attributes_forのような1行で大きな効果を有するコードは、その動作を理解できていないと、予想外のエラーの原因になります。便利なものほどその本質の理解を心がけようと思いました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0