ウェブエンジニア珍道中

日々の技術的に関する経験を書いていきます、脱線もします。

Rails5でnested attributesに詰まった話

早速Rails5を触ってると、nested attributes周りで詰まったので紹介します。

症状

  • 全ての項目を入れてもバリデーションに引っかかって保存できない。

モデル

ここではモデル名をParent, Childとします。

class Parent < ApplicationRecord
  has_many :children
  accepts_nested_attributes_for :children
end
class Child < ApplicationRecord
  belongs_to :parent
end

対応

以下の用に書くと動くようになりました。

class Child < ApplicationRecord
  belongs_to :parent, optional: true
end

原因

@parent.errorsでバリデーションの内容を見てみると
子テーブルにおいて親テーブルのIDが無いという内容でした。

で、調べ進めていくとRails5による新しい挙動が原因のようです。

qiita.com

つまりChildモデル内でparent_idが自動的にrequired: true
バリデーションがかかるようになっていたみたいです。

そしてRailsでバリデーションと保存の順番は大まかに

  1. Parentのバリデーション
  2. Childのバリデーション
  3. Parentの保存処理
  4. Childの保存処理

の順で行われ、Parentの保存がされて生まれたIDが
Childのparent_idに入ります。

しかし、Childモデル内でparent_idが必須になっているために
はじめのParentのバリデーションの時点で
「Childにparent_idねーよ!」と怒って終了するようです。

なのでbelongs_tooptional: trueを付けて
parent_id必須を無くしたという感じです。

「いや、そもそもrequired: trueつけんなよ」 という方は
こちらに取り方が書いてました。

Rails5 の落とし穴 - zeny.io

設定でRails4と同じ挙動にできるみたいですね。
どっちがいいのやら。

他にもRails5でハマった時は紹介したいと思います。