假设我有一个模型Warehouse
,一个模型Car
和一个模型Dealer
。
模型Car
就像:
attr_accessible :make, :year
belongs_to :warehouse
belongs_to :dealer
controller Cars
就像:
def create
car = current_dealer.find(params[:car][:warehouse_id]).cars.new(params[:car])
car.save!
end
Cars#new
的观点如下:
<%= semantic_form_for @car do |f| %>
<%= f.inputs do %>
<%= f.input :warehouse, :include_blank => false %>
<%= f.input :make %>
<%= f.input :year %>
<% end %>
<% end %>
经销商可以在添加汽车时选择仓库,以上代码可以防止大规模分配(也就是经销商将汽车添加到他们不拥有的仓库),但它引发了一个例外{{em> 1}}无法进行质量分配,这是因为它带有参数:warehouse_id
。
如何在不手动分配属性的情况下摆脱该错误?那反正是一个好方法吗?
P.S。我试过params[:car][:warehouse_id]
,但这看起来不是正确的做法。
答案 0 :(得分:2)
因为:warehouse_id不是汽车的质量可分配属性,您不能将其作为汽车的属性从表单发布。如果你以这种方式命名你的参数,即使你在控制器中没有对它们进行任何操作,Rails也会引发质量分配错误。
而不是(非特定的):
<%= f.hidden_field :warehouse_id %>
做的:
<%= hidden_field_tag :warehouse_id, @car.warehouse_id %>
我对formtastic不太熟悉,但我认为上面的那行应该有用。
在控制器中:
def create
@car = current_dealer.find(params[:warehouse_id]).cars.new(params[:car])
@warehouse = Warehouse.find(params[:warehouse_id])
@car.warehouse = @warehouse
@car.save!
end
我知道,这有点单调乏味。不幸的是,保护代码需要更多的努力。
<强>结论强>:
params[:car][:warehouse_id]
=质量分配
答案 1 :(得分:1)
停止使用attr_accessible,请使用strong_parameters
删除attr_accessible :make, :year
将gem 'strong_parameters'
添加到您的Gemfile。
将include ActiveModel::ForbiddenAttributesProtection
添加到您的每个模型中。
然后,替换:
car = current_dealer.find(params[:car][:warehouse_id]).cars.new(params[:car])
使用:
car = current_dealer.find(params[:car][:warehouse_id]).cars.new(params.require(:car).permit([:make, :year]))
答案 2 :(得分:0)
质量分配仅确定是否可以通过表单(或API)设置字段,它不控制可以设置的内容。问题是您正在尝试使用质量分配来控制数据的验证或限制。在您的情况下,您希望能够通过用户选择的选择列表保存warehouse_id
,因此它必须可用于批量分配,以使用标准参数方法来创建汽车。
建议的解决方案是首先使用Formtastic select
输入来限制经销商可以选择的值。虽然我不知道您目前如何限制仓库,但一般版本是:
f.input :warehouse, :as => :select, :collection => "Whatever your selection rule is"
这应该确保只有经销商可用的仓库列表实际显示在表格中。
这并不能解决具有足够技术知识的人可以更改URL中的warehouse_id并仍然发布到他们不拥有的仓库的问题。因此,您还应该在Car模型上添加验证,以确保只有属于经销商的仓库才是有效的选择。
这应该可以解决您的问题,为您需要的仓库_id保留质量分配,同时仍然确保经销商只能选择属于他们的仓库。