0

我有一个汽车模型和一个品牌模型(每个都有_and_belongs_to_many)。我正在尝试为汽车创建一个新品牌。汽车模型接受品牌的嵌套属性。

当我尝试

@car = Car.find(params[:car_id])
@brand = @car.brands.build(params[:brand])

我收到批量分配错误:

Can't mass-assign protected attributes: brands

品牌控制器:

class BrandsController < ApplicationController
 def create
  debugger
  @car = Car.find(params[:car_id])
  @brand= @car.brands.build(params[:brand])
  if @brand.save
   redirect_to @car
  else
   #do something
  end
 end 
end

调用调试器

pp params

显示:

"brand"=>{"brands"=>{"name"=>"BMW"}},
"commit"=>"Create Brand",
"action"=>"create",
"controller"=>"brands",
"car_id"=>"4"}

视图如下所示:

<%= form_for([@car, @car.brands.build]) do |f| %>
    <div class="field">
        <%= f.fields_for :brands do |a| %>
            <%= a.text_field :name, placeholder: "New Brand" %>
        <% end %>
    </div>
    <p><%= f.submit %></p>
<% end %>

我希望应用程序是安全的,所以我想单独设置品牌属性,而不是传递整个“品牌”哈希(顺便说一句不起作用)。如何获得品牌名称?就像是

params[:brands].name?

编辑:

我可以使用“params[:brand][:brands][:name]”获取品牌名称。现在事实证明,brands 表没有 car_id,因为它通过连接表连接到汽车。

4

2 回答 2

1

尽管在某些情况下让一个模型接受另一个模型的属性是一个有用的工具,但它往往很麻烦,并且不仅在模型级别,而且在控制器和视图层都违反了单一职责原则。如果您的设计需要更改,最终会使重构变得更加困难。

遵循 REST 的理念,而不是通过汽车创建品牌,而是使用 BrandsController 来处理品牌的生命周期。

至于您对安全性的要求,假设您正确使用 attr_accessible,手动设置模型的属性并不能提供更多的安全性,然后传递整个参数哈希。给它一个可接受参数的白名单将告诉 AR 界面应该拒绝其他所有内容。

class Brand < ActiveRecord::Base
  attr_accessible :name
end

因此,如果一个品牌属于汽车,并且有人试图通过将 car_id 破解为它会从哈希中拒绝 car_id 的形式来改变关系,甚至可能根据您的设置引发异常。

config.active_record.mass_assignment_sanitizer = :strict

这将导致ActiveModel::MassAssignmentSecurity::Error输出到日志中的不仅仅是警告。

于 2013-02-15T16:31:57.550 回答
1
<%= form_for @car do |f| %>
  <div class="field">
    <%= f.fields_for :brands do |a| %>
        <%= a.text_field :name, placeholder: "New Brand" %>
    <% end %>
  </div>
<p><%= f.submit %></p>
<% end %>

在您的模型中:

class Car < ActiveRecord::Base
  has_many :brands
  accepts_nested_attributes_for :brands
  attr_accessible :brand_attributes
end
于 2013-02-15T15:46:20.280 回答