Rails使用嵌套属性保存失败的验证

时间:2019-03-15 22:29:55

标签: ruby-on-rails

user.rb

has_many :characters
accepts_nested_attributes_for :characters

after_save self.characters.create

character.rb

belongs_to :user

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

seeds.rb

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

我正在尝试使用find_or_initialize_by设置我的seed.rb文件,以便在每次向记录添加属性时都可以运行rails db:seed。但是运行rails db:seed会出现此错误:

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

如何通过嵌套属性进行验证?

2 个答案:

答案 0 :(得分:1)

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

要验证关联的记录,请使用validates_associated method

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

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

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

<%= 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 %>

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

答案 1 :(得分:0)

这里accepts_nested_attributes_for做您想要实现的事后保存挂钩。因此,这里发生的是,当您尝试使用字符属性保存用户时,默认情况下(因为您接受accepts_nested_attributes_for),两个对象均被保存。然后,您还具有一个after save钩子来创建您的字符,该钩子将尝试再次创建字符,从而引发唯一约束验证错误。您将不需要在这里的after_save钩子。