首页 > 解决方案 > Rails 使用嵌套属性保存失败的验证

问题描述

用户.rb

has_many :characters
accepts_nested_attributes_for :characters

after_save self.characters.create

字符.rb

belongs_to :user

validates :username, presence: true, uniqueness: true
validates :user, presence: true

种子.rb

user = User.find_or_initialize_by(email: "barry@websmash.com")
user.characters_attributes = [{ name: "Barry", username: "barry" }]
user.save!

我正在尝试设置我的seeds.rb 文件,find_or_initialize_by以便rails db:seed在我想向记录添加属性时运行。但是运行rails db:seed给出了这个错误:

验证失败:字符用户名已被占用

如何通过嵌套属性获得验证?

标签: ruby-on-rails

解决方案


问题是after_save self.characters.create。它不仅完全没有必要,而且会触发验证失败,因为您正在创建没有任何属性的用户记录。

要验证关联记录,请使用以下validates_associated方法

class User < ApplicationRecord
  has_many :characters
  accepts_nested_attributes_for :characters
  validates_associated :characters
end

这将遍历关联的记录并添加characters are invalid到父用户记录上的错误,除非所有字符都有效。

如果要显示每个字符的错误,则必须遍历每个嵌套记录上的错误对象:

<%= form_with(model: user, local: true) do |form| %>
  # ...
  <fieldset>
    <legend>Characters</legend>
    <%= form.fields_for(:characters) do |cf| %>
      <% cf.object.tap do |character| %>
        <% if character.errors.any? %>
        <div class="errors">
          <h2><%= pluralize(character.errors.count, "error") %> prohibited this character from being saved:</h2>
          <ul>
          <% character.errors.full_messages.each do |msg| %>
            <li><%= msg %></li>
          <% end %>
          </ul>
        </div>
        <% end %>
      <% end %>
      <div class="character">
         <div class="field">
           <%= cf.label :username %>
           <%= cf.text_field :username %>
         </div>
      </div>
    <% end %>
  </fieldset>
  # ...
<% end %>

这当然可以通过为错误消息创建通用部分来清除。


推荐阅读