据我所知,这是一个视图和控制器问题。
我需要允许用户在我的一个数据库表中编辑多个记录。 Railscast 165处理类似的情况,但对我来说并不是很重要:http://railscasts.com/episodes/165-edit-multiple
我有一套固定的产品,我需要让用户为这些产品添加相关品种。我考虑过更简单的解决方案,要求用户转到产品页面,并一次编辑一个单独的产品,但这对我的应用程序不起作用。相反,我需要为这一项任务提供更多的管理风格功能。
这里的模型关系很简单。产品has_many
品种和品种belongs_to
产品。在我的用户界面中,我只是让用户从包含网站上所有可用产品的下拉菜单中选择产品,然后用户可以在文本输入中键入各种名称。例如,如果我们谈论苹果,那么用户可以从产品下拉菜单中选择苹果,并且他可以输入“fuji”和各种各样的苹果。我只需要将product_id
和品种[name]保存到品种表中。但是,我需要一次为多个记录执行此操作。
目前,我已经通过下拉列表显示了正确的产品选择。问题似乎是变量输入在html中呈现如下:
<label for="nil_class_variety">Variety</label>
<input id="nil_class_name" name="nil_class[name]" size="30" type="text" />
为了渲染表单的一部分,我遵循Advanced Rails Recipes多模型表单技术(即Ryan Bates方式)。我花了大约10个小时尝试这样做,似乎我现在非常接近,但我不知道这个问题到底是什么。
这是我的设置:
def edit_multiple
@products = Product.find(:all)
end
def update_multiple
params[:product][:existing_variety_attributes] ||= {}
@products = Product.find(:all)
if @products.each do |product|
product.update_attributes!(params[:product].reject { |k,v| v.blank? })
end
flash[:notice] = "Updated products!"
redirect_to edit_user_path(self.current_user)
else
render :action => 'edit'
flash[:error] = "Something went wrong. Please try again."
end
end
map.resources :products, :collection => { :edit_multiple => :get, :update_multiple => :put}
<%= error_messages_for :product %>
<% form_for :product, :url => update_multiple_products_path, :html => { :method => :put } do |f| %>
<div id="varieties">
<%= render :partial => 'variety' %>
</div>
<p><%= add_variety_link "+ Add another variety" %></p>
<%= f.submit 'Submit Varieties' %>
<%end%>
注意:目前,我不会让用户编辑他们提交的品种。所以我从Ryan Bates技术中删除了以下一行,因为它抛出了一个错误而我认为我不需要它,但我可能错了:<%# new_or_existing = variety.new_record? ? 'new' : 'existing' %>
这就是我在这个_variety partial中所拥有的:
<% prefix = "product[new_variety_attributes][]" %>
<% fields_for @variety do |variety_form| -%>
<%= collection_select(:product, :product_id, Product.all, :id, :name, {:prompt => true}) %>
<%= variety_form.label :variety %>
<%= variety_form.text_field :name %>
<%= link_to_function "- Remove Variety", "$(this).up('.variety').remove()" %>
<%end -%>
注意:目前您看到的javascript内容正在运行。在edit_multiple视图页面上,我可以动态添加和删除产品/品种输入。正如我所提到的,下拉列表也正常填充。因此,我似乎只需要将各种输入正确渲染并让控制器正确处理它。谢谢你的帮助!
当我从下拉列表中选择一个产品并在品种输入中键入名称时,提交会抛出以下错误并跟踪:
ActiveRecord::UnknownAttributeError in ProductsController#update_multiple
unknown attribute: product_id
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.3/lib/active_record/base.rb:2740:in `attributes='
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.3/lib/active_record/base.rb:2736:in `each'
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.3/lib/active_record/base.rb:2736:in `attributes='
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.3/lib/active_record/base.rb:2628:in `update_attributes!'
/Users/michael/dev/fresh/app/controllers/products_controller.rb:74:in `update_multiple'
/Users/michael/dev/fresh/app/controllers/products_controller.rb:73:in each'
/Users/michael/dev/fresh/app/controllers/products_controller.rb:73:in
update_multiple'
日志显示正确的product_id和我输入的正确名称,但您可以看到它正在调用nil类:
Processing ProductsController#update_multiple (for 127.0.0.1 at 2009-10-08 07:31:05) [PUT]
Parameters: {"commit"=>"Submit Varieties", "authenticity_token"=>"zzkveSe7qzv2NY8WPrR2cYS376u6DBiz8Vc9iNFLQy8=", "product"=>{"product_id"=>"5"}, "nil_class"=>{"name"=>"yellow"}}
当我尝试输入多个产品/品种记录时,日志除了第一个以外没有识别任何内容。当我输入一个产品/品种记录时,我得到的结果相同。
答案 0 :(得分:1)
对你的问题的简短回答是@variety在fields_for @variety中未定义。 /app/views/products/_variety.html.erb中该行的正确版本为
<% fields_for :variety do |variety_form| -%>
你的标签行也有一点点挑剔。
<%= variety_form.label :variety %>
应该是
<%= variety_form.label :name, "Variety" %>
我不知道您的目标是一次更新多个产品和品种,还是更新单个产品的品种。假设后者,您应该使用accepts_nested_attributes_for(向下滚动到嵌套属性示例),看起来它可能是一种更简单的方法。另请参阅github Complex-Forms-Example存储库以进行工作演示。
但事实并非如此。在我看来,您的javascript函数正在为产品和品种添加表单/删除值。
这将在控制器中用于添加品种,但需要更多的工作来移除现有品种。但是您链接的railscast提供了将它们组合在一起所需的所有信息。