当表单对象涉及两个具有相同属性名称的模型时,错误附加到错误的输入字段

Error is attached to wrong input field when a form object involves two models with the same attribute name

提问人:pinkfloyd90 提问时间:12/2/2022 最后编辑:pinkfloyd90 更新时间:12/3/2022 访问量:193

问:

我正在处理一个表单对象,该对象涉及使用许多相关模型(例如嵌套属性)更新记录。UserAddressPhone

和 模型都有一个属性,因此我为每个 HTML 输入和表单对象属性命名不同。AddressPhonenumber

<%= simple_form_for @user_form, method: :patch do |f| %>

  <%= f.input :number %>
  <%= f.input :phone %>

<% end %>

控制器:

  def edit
    @user_form = UserForm.new(@user)
  end

  def update
    @user_form = UserForm.new(@user, update_params)
    if @customer_update.save
      redirect_to :users_path
    else
      render :edit
    end
  end

  def update_params
    params.require(:user_form).permit(:number, :phone)
  end

简化表单对象:

class UserForm
  include ActiveModel::Model
  include ActiveModel::Validations::Callbacks

  attr_accessor :number
                :phone
  

  attr_reader :user

  validate :validate_children


  def initialize(user, update_params = nil)
    @user = user

    super(update_params)
  end

  def save
    user.assign_attributes(user_params)
    return false if invalid?

    user.save
  end  
  
  
  def user_params
    {}.tap do |p|
      p[:address_attributes] = {number: number}
      p[:phone_attributes] = {number: phone}
    end.compact
  end


  def validate_children
    promote_errors(user.associated_model.errors) if associated_model.invalid?
  end


  def promote_errors(child_errors)
    child_errors.each do |attribute, message|
      errors.add(attribute, message)
    end
  end
end

我将验证委托给实际和模型,其中有一个AddressPhone

validates :number, presence: true

因此,如果对任一模型进行验证,则错误将提升到表单对象,并显示在无效的输入字段上。

@user_form.errors.keys
=> [:"phone.number", :number]

@user_form.errors.full_messages
=> ["Number can't be blank"]

问题是,例如,如果在提交表单时将字段留空,因为无效的实际属性是 ,则错误将显示在我的表单的输入字段中,或者换句话说,错误会在字段中呈现,因为表单输入被调用相同()。:phonePhonenumber:numberPhonenumberAddressnumberf.input :number

有没有办法改变它或以不同的方式促进错误,这样就不会发生这种情况?上面的代码显然是愚蠢的,如果需要细节,请告诉我。

Ruby-on-Rails 表单 验证 ActiveRecord 错误处理

评论

0赞 pinkfloyd90 12/2/2022
最后,最合理的解决方法是绕过simple_form错误呈现,方法是不对这些字段使用simple_form输入,并手动为每个字段呈现错误(检查是否存在错误。form_object.errors.full_messages_for(:key)

答:

0赞 max 12/2/2022 #1

这似乎是很多不必要的复杂性。

你通常在 Rails 中设置它的方式是使用(和 SF 包装器):fields_forsimple_fields_for

<%= form_with(model: @user) do |form| %>
  <%= form.fields_for(:phone) do |phone_fields| %>
    <pre><%= phone_fields.object.errors.full_messages.inspect %></pre>
  <% end %>

  <%= form.fields_for(:number) do |number_fields| %>
    <pre><%= number_fields.object.errors.full_messages.inspect %></pre>
  <% end %>
<% end %>

这些方法生成一个表单生成器,调用获取表单生成器包装的模型实例。这样可以很容易地将错误一起显示或按属性显示并使其正确 - 如果您正在处理一对多或多对多而不是一对一,则尤其如此。object