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
会出现此错误:
验证失败:字符用户名已被使用
如何通过嵌套属性进行验证?
答案 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钩子。