如何以正确的方式防止关联群众的分配?

时间:2012-07-01 19:40:46

标签: ruby-on-rails mass-assignment

假设我有一个模型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],但这看起来不是正确的做法。

3 个答案:

答案 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保留质量分配,同时仍然确保经销商只能选择属于他们的仓库。

相关问题