I have a many-to-many relationship between Recipes and Ingredients . I am trying to create a form that allows me to add an ingredient to a recipe.
(Variants of this question have been asked repeatedly, I spent several hours on it, but mostly confused by what accepts_nested_attributes_for does.)
Before you get scared of the whole code below, I hope you see that this is really a basic question. These are not scary details ...
Mistakes
When I show the form for creating a recipe, I get the error message "uninitialized constant Recipe :: IngredientsRecipe", pointing to a line in my form
18: <%= f.fields_for :ingredients do |i| %>
If I change this line to make the "ingredients" the only ones
<%= f.fields_for :ingredient do |i| %>
then the form will be displayed, but when I save, I get a mass assignment error Can't mass-assign protected attributes: ingredient .
Models (in 3 files, named accordingly)
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
Controllers
As RESTful resources generated by rails generate scaffold
And, since the plural of the βrecipeβ is irregular, inflections.rb
ActiveSupport::Inflector.inflections do |inflect| inflect.irregular 'recipe', 'recipes' end
View ( 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 %>
Environment
Tried some things
If I change the view of f.fields_for :ingredient , then the form loads (it correctly finds Recipe::IngredientRecipe , but then when I save, I get a mass assignment error as above). Here is the magazine
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'
and failed lines in the controller are just
@recipe = Recipe.new(params[:recipe])
Therefore, the passed parameters, including nested attributes, are incorrect. But I tried many options that fix the one-time-another. What? I do not understand?