カテゴリー:
Rails
タグ:
 Rails has_many validation validate accepts_nested_attributes_for

このエントリーをはてなブックマークに追加
更新日時:
2013年10月03日(木)
作成日時:
2013年10月03日(木)

前の記事 / 次の記事

accepts_nested_attributes_for を使って配列をネストさせた場合に
配列の要素ごとに個別にエラーメッセージを表示させるには、

親モデルの中で 配列用のカスタムバリデーション を定義して、
親モデルの has_many に validate: false を指定 する。

例えば次のようなモデルを定義して

class User < ActiveRecord::Base
  has_many :items
  accepts_nested_attributes_for :items
end

バリデーションした場合、

@user.valid?

items[0].name とitems[1].name にエラーがあってもそれは区別されることなく

@user.errors["items.name"]

に格納される。というか上書きされる。
だから例えば、 items[0].name と items[1].description にエラーがあった場合、

@user.errors["items.name"]        # items[0] のエラーが入っている
@user.errors["items.description"] # items[1] のエラーが入っている

という状態になる。

最終的に全てのバリデーションが通らなければ保存出来ないので
システム的に不整合が生じることはないのだけど、
ビューでエラーメッセージを表示させてる場合ちょっと気持ち悪い。

で、配列の要素ごとにエラーメッセージを表示させるには、
親モデルでバリデーションを回すしかないのかなと。

class User < ActiveRecord::Base
  # validate: false を指定しないとエラーメッセージが二重に生成される
  has_many :items, validate: false
  accepts_nested_attributes_for :items

  validate :validate_items

  private

    def validate_items
      items.each do |item|
        return if item.valid?

        item.errors.full_messages.each do |full_messsage|
          errors.add(:items, full_message)
        end

        item.errors.clear
      end
    end
end

Rails的に何か指定したらこういう風になりそうな気もするんだけど。
とりあえず分からなかった。

あとデフォルト設定で field_with_error で色付けしてる場合はこの方法だと色が付かなくなる。

参考: stackoverflow: How do I validate members of an array field?