What I try to do is a simple form for Plate where you can choose which Ingredients you want. The number and name of Ingredients may vary by day.
Every time a new Plate is created, it created 4 new Choices with plate_id
and ingredient_id
and a boolean chosen
.
plate_id
is from the new plate create and ingredient_id
should be the id of the already existing ingredient in my database, and chosen
it's if the ingredient should be in the plate.
Here is my classes Plate, Choice and Ingredient :
class Plate < ActiveRecord::Base
has_many :choices
has_many :ingredients, through: :choices
accepts_nested_attributes_for :choices
end
class Choice < ActiveRecord::Base
belongs_to :plate
belongs_to :ingredient
accepts_nested_attributes_for :ingredient
end
class Ingredient < ActiveRecord::Base
has_many :choices
has_many :plates, through: :choices
end
And my Plate nested form looks like this :
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<%= f.fields_for :choices do |fc| %>
<%= fc.check_box :chosen %>
<%= fc.fields_for :ingredient do |fi| %>
<%= fi.text_field(:name)%> <br />
<% end %>
<% end %>
And finally my Plate controller :
def new
@plate = Plate.new
@choice1 = @plate.choices.build
@choice2 = @plate.choices.build
@choice3 = @plate.choices.build
@choice4 = @plate.choices.build
@ingredient1 = Ingredient.find_by_name('peach')
@ingredient2 = Ingredient.find_by_name('banana')
@ingredient3 = Ingredient.find_by_name('pear')
@ingredient4 = Ingredient.find_by_name('apple')
@choice1.ingredient_id = @ingredient1.id
@choice2.ingredient_id = @ingredient2.id
@choice3.ingredient_id = @ingredient3.id
@choice4.ingredient_id = @ingredient4.id
end
def plate_params
params.require(:plate).permit(:name, choices_attributes: [:chosen, ingredient_attributes: [ :name]])
end
My problem is that when I create a new plate, it create new ingredients with same name as the chosen one (but with different id of course) and Choices had the ingredient_id of the new ingredients created.
I tried to add the :id
in the nested attributes :
params.require(:plate).permit(:name, choices_attributes: [:chosen, ingredient_attributes: [:id, :name]])
Bu when I do that, I go an error :
Couldn't find Ingredient with ID=1 for Choice with ID=
I searched for answers but couldn't find any, I guess I don't know Rails params, form and nested attributes enough to understand where is the problem.
Thanks for your help !
ps : It's my first question on Stack Overflow, please let my know if anything is wrong with my question
You don't need accepted_nested_parameters_for :ingredient
since the form isn't designed to let you create ingredients or edit ingredients.
Better that you just use collection_select
to select an existing ingredient as part of the choice
record (that is, just save the ingredient_id).
<%= f.fields_for :choices do |fc| %>
<%= fc.check_box :chosen %>
<%= fc.collection_select(:ingredient_id, Ingredient.all, :id, :name, prompt: true) %>
<% end %>
And your attributes should then be...
params.require(:plate).permit(:name, choices_attributes: [:chosen, :ingredient_id])
If you just want to show the ingredient but not allow the user to change which ingredient, you can do
<%= f.fields_for :choices do |fc| %>
<%= fc.check_box :chosen %>
<%= fc.hidden_field :ingredient_id %>
<%= Ingredient.find(fc.object.ingredient_id).name %>
<% end %>
You're finding the ingredient_id in the object encompassed by the form object fc
and using that id to access the Ingredient, and retrieving the name attribute.
Also notice the hidden field for the :ingredient_id
... to make sure it's returned in the attribute hash.