我试图让用户通过自定义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"的方式完成上述工作有任何想法,请告诉我:(