Tom*_*son 4 activerecord ruby-on-rails has-many-through nested-attributes ruby-on-rails-3
我在食谱和配料之间有多对多的关系.我正在尝试构建一个允许我在配方中添加成分的表单.
(这个问题的变体已被反复询问,我花了好几个小时,但基本上对于accepts_nested_attributes_for它的含义感到困惑.)
在您对以下所有代码感到害怕之前,我希望您会发现它确实是一个基本问题.这是非恐怖的细节......
当我显示一个表单来创建一个食谱时,我收到错误"未初始化的常量Recipe :: IngredientsRecipe",指向我的表单中的一行
18: <%= f.fields_for :ingredients do |i| %>
Run Code Online (Sandbox Code Playgroud)
如果我改变这一行,使"成分"单数
<%= f.fields_for :ingredient do |i| %>
Run Code Online (Sandbox Code Playgroud)
然后表单显示,但是当我保存时,我得到一个质量分配错误Can't mass-assign protected attributes: ingredient.
class Recipe < ActiveRecord::Base
attr_accessible :name, :ingredient_id
has_many :ingredients, :through => :ingredients_recipes
has_many :ingredients_recipes
accepts_nested_attributes_for :ingredients
accepts_nested_attributes_for :ingredients_recipes
end
class Ingredient < ActiveRecord::Base
attr_accessible :name, :recipe_id
has_many :ingredients_recipes
has_many :recipes, :through => :ingredients_recipes
accepts_nested_attributes_for :recipes
accepts_nested_attributes_for :ingredients_recipes
end
class IngredientsRecipes < ActiveRecord::Base
belongs_to :ingredient
belongs_to :recipe
attr_accessible :ingredient_id, :recipe_id
accepts_nested_attributes_for :recipes
accepts_nested_attributes_for :ingredients
end
Run Code Online (Sandbox Code Playgroud)
作为RESTful资源生成的 rails generate scaffold
inflections.rbActiveSupport::Inflector.inflections do |inflect|
inflect.irregular 'recipe', 'recipes'
end
Run Code Online (Sandbox Code Playgroud)
recipes/_form.html.erb)<%= form_for(@recipe) do |f| %>
<div class="field">
<%= f.label :name, "Recipe" %><br />
<%= f.text_field :name %>
</div>
<%= f.fields_for :ingredients do |i| %>
<div class="field">
<%= i.label :name, "Ingredient" %><br />
<%= i.collection_select :ingredient_id, Ingredient.all, :id, :name %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Run Code Online (Sandbox Code Playgroud)
如果我更改视图f.fields_for :ingredient然后表单加载(它找到Recipe::IngredientRecipe正确,但是当我保存时,我得到如上所述的质量分配错误.这是日志
Started POST "/recipes" for 127.0.0.1 at 2012-11-20 16:50:37 -0500
Processing by RecipesController#create as HTML
Parameters: {"utf8"=>"?", "authenticity_token"=>"/fMS6ua0atk7qcXwGy7NHQtuOnJqDzoW5P3uN9oHWT4=", "recipe"=>{"name"=>"Stewed Tomatoes", "ingredient"=>{"ingredient_id"=>"1"}}, "commit"=>"Create Recipe"}
Completed 500 Internal Server Error in 2ms
ActiveModel::MassAssignmentSecurity::Error (Can't mass-assign protected attributes: ingredient):
app/controllers/recipes_controller.rb:43:in `new'
app/controllers/recipes_controller.rb:43:in `create'
Run Code Online (Sandbox Code Playgroud)
并且控制器中的故障线很简单
@recipe = Recipe.new(params[:recipe])
Run Code Online (Sandbox Code Playgroud)
因此传递的参数(包括嵌套属性)在某种程度上是不正确的.但我已经尝试了许多修复 - 一次破坏 - 另一种.我什么不明白?
感谢所有人的线索,我发现我的方法出了什么问题.这是我解决它的方式.
我最初尝试使用简单的HABTM多对多关系,其中连接表是按照标准Rails约定命名的:ingredients_recipes.然后我意识到,在某种程度上,accepts_nested_attributes_for它是为一对多的关系而设计的.所以我转换为使用has_many_through,创建了一个模型IngredientsRecipes.
这个名称是核心问题,因为在使用build创建表单元素时,Rails需要能够从复数转换为单数.这导致它寻找不存在的类Recipe::IngredientsRecipe.当我更改我的表单以便使用fields_for :ingredient显示的表单时,但仍然无法使用批量分配错误进行保存.当我加入时它甚至失败:ingredients_attributes了attr_accessible.当我加入时,它仍然失败@recipe.ingredients.build了RecipesController#new.
将模型更改为单数形式是解决问题的最终关键. IngredientsRecipe会有用,但我选择了RecipeIngredients,因为它更有意义.
总结一下:
accepts_nested_attributes_for带has_and_belongs_to_many; 需要has_many与through选择.(谢谢@kien_thanh)accepts_nested_attributes_for创建一个必须添加到attr_accessible表单中的访问器<plural-foreign-model>_attributes,例如Recipe我添加attr_accessible :name, :ingredients_attributes(感谢@beerlington)new控制器的方法中显示表单之前,必须build在创建新实例后调用外部模型,如3.times { @recipe.ingredients.build }.这导致HTML的名称像recipe[ingredients_attributes][0][name](Thanks @bravenewweb)| 归档时间: |
|
| 查看次数: |
3711 次 |
| 最近记录: |