如何让Rails在验证失败时使用fields_for时只显示/允许新记录



我试图让用户通过自定义URL一次添加多个付款,但如果存在验证问题,就会遇到现有记录的问题。

URL"/setup/payments"在表单中预先填充了两个付款示例,让他们了解可以添加的付款类型。

如果验证有问题,即他们忘记向其中一个字段添加值,则表单会在@company.payments中添加任何现有项目,这些项目在呈现的HTML:中看起来像这样

<input id="company_payments_attributes_0_id" name="company[payments_attributes][0][id]" type="hidden" value="104">

如果用户试图再次提交表单,它将遇到其中任何一个的验证问题,因为表单中既没有名称也没有值。

如果存在验证问题,并且我需要再次提交表单,我如何确保@company.payments中的现有项目不会添加到此表单?

以下是我正在使用的所有代码的示例:

config/routes.rb

get '/setup/payments', :to => 'companies#setup_payments', :as => :setup_payments
post '/setup/payments', :to => 'companies#save_payments', :as => :save_payments

应用程序/模型/公司.rb

class Company < ActiveRecord::Base
    belongs_to :user
    has_many :payments
    accepts_nested_attributes_for :payments
end

应用程序/模型/支付.rb

class Payment < ActiveRecord::Base
    belongs_to :company
    validates :name, :presence => { :message => "Name is required" }
    validates :value, :presence => { :message => "Value is required" }
end

app/controllers/companies_controller.rb

class CompaniesController < ApplicationController
    def setup_payments
       @company = curent_user.company
       @payments = [
       {
          :name => 'Coffee',
          :value => 5
       },
       {
          :name => 'Breakfast',
          :value => 10
       }
       ]
       @company.payments.build(@payments)
    end
    def save_payments
       @company = curent_user.company
       if @company.update(company_params)
          redirect_to root_path and return
       else
          render :setup_payments
       end
    end
    private
    def company_params
       params.require(:company).permit(:name, payments_attributes: [:name, :value, :_destroy])
    end
end

app/views/components/setup_payments.html.erb

<% if @company.errors.any? %>
   <h2>We found <%= pluralize(@company.errors.count, "error") %>:</h2>
   <ol>
      <% @company.errors.each do |attr, msg| %>
      <li><%= msg %></li>
      <% end %>
   </ol>
<% end %>
<%= nested_form_for @company, :url => save_payments_path, :method => 'post' do |f| %>
   <% if params[:company].nil? %>
      <%= f.fields_for :payments, @company.payments.build(@payments) do |payment| %>
         <%= render :partial => 'payments', :locals => { :payment => payment } %>
      <% end %>
   <% else %>
      <%= f.fields_for :payments do |payment| %>
         <%= render :partial => 'payments', :locals => { :payment => payment } %>
      <% end %>
   <% end %>
   <%= f.link_to_add "Add Another", :payments %>
   <%= f.button "Save Payments" %>
<% end %>

app/views/components/_payments.html.erb

<% if payment.object.new_record? %>
  <%= payment.text_field :name %>
  <%= payment.text_field :value %>
<% end %>

如果要忽略任何名称或值为空的嵌套支付,则可以在accepts_nested_attributes_for上使用recject_If选项。

accepts_nested_attributes_for :payments, reject_if: proc { |attributes| attributes['name'].blank? || attributes['value'].blank? }

因此,当你保存一个既没有"名称"也没有"价值"属性的现有付款时,它只会忽略它们。

另一种选择是不在app/views/companys/setup_payments.html.erb 中显示现有的支付记录

app/controllers/companies_controller.rb

def setup_payments
   @company = curent_user.company
   @example_attributes = [
   {
      :name => 'Coffee',
      :value => 5
   },
   {
      :name => 'Breakfast',
      :value => 10
   }
   ]
   @payments = @company.payments.build(@example_attributes)
end

app/views/components/setup_payments.html.erb

<% if params[:company].nil? %>
  <%= f.fields_for :payments, @company.payments.build(@example_attributes) do |payment| %>
     <%= render :partial => 'payments', :locals => { :payment => payment } %>
  <% end %>
<% else %>
  <%= f.fields_for :payments, @payments do |payment| %>
     <%= render :partial => 'payments', :locals => { :payment => payment } %>
  <% end %>

谢谢Simon,我最终通过以下代码更改解决了这个问题:

accepts_nested_attributes_for :payments, :reject_if => :all_blank

这样,只有新项目才不会通过验证。如果我试图拒绝名称或值为空的项目,那么我可能会遇到这样的情况:表单中的"新项目"没有通过验证,因为其中一个是空的。我只想让新的项目通过验证,而不是现有的项目。

第页。S.如果还不清楚的话,我对Rails还很陌生,所以如果有人对我如何以更"Railsy"的方式完成上述工作有任何想法,请告诉我:(

相关内容

  • 没有找到相关文章

最新更新