Reputation: 673
Using Rails 6.0.3.3 and ruby '2.6.0'.
I have these 3 models connected via a has_many through
relation.
class Recipe < ApplicationRecord
has_many :layers
has_many :glazes, through: :layers
end
class Glaze < ApplicationRecord
has_many :layers
has_many :recipes, through: :layers
end
class Layer < ApplicationRecord
belongs_to :recipe
belongs_to :glaze
# there is a column named "coat_type" here that I would like to set
end
Everything is working great for creating a new Recipe
and it automagically creating its related Layer
record. But now I would like to also set a coat_type
attribute on the Layer
record when it's created, but I can't seem to figure out how I could do something like that.
The Form View Partial
= form_with model: recipe, local: true do |form|
%p
= form.label :name
%br
= form.text_field :name
%p
= form.label :description
%br
= form.text_area :description
.recipe-glaze
= form.collection_select(:glaze_id, Glaze.all, :id, :name, { prompt: "Select Glaze" }, { name: 'recipe[glaze_ids][]' })
.recipe-glaze
= form.collection_select(:glaze_id, Glaze.all, :id, :name, { prompt: "Select Glaze" }, { name: 'recipe[glaze_ids][]' })
%p
= form.submit
The Controller Create Action (and strong params acton)
def create
@recipe = Recipe.new(recipe_params)
if @recipe.save
redirect_to @recipe
else
render 'new'
end
end
private
def recipe_params
params.require(:recipe).permit(:name, :description, glaze_ids: [])
end
Ideally, I would be able to add another select box in the form and the user would use that to set the coat_type
of the Layer
record that will be created. But I can't figure out how I could pass that into the controller and have it know what to do with that value.
Is this something that is possible, or am I approaching this incorrectly?
Upvotes: 0
Views: 334
Reputation: 673
So I actually ended up stumbling upon the "cocoon" gem thanks to this comment. By following the setup instructions for "cocoon", I was able to tweak my code to do what I needed.
My Recipe
model changed to this ::
class Recipe < ApplicationRecord
has_many :layers, inverse_of: :recipe
has_many :glazes, through: :layers
accepts_nested_attributes_for :layers, reject_if: :all_blank, allow_destroy: true
end
My controller's strong params action changed to this ::
private
def recipe_params
params.require(:recipe).permit(:name, :description, layers_attributes: [:id, :glaze_id, :coat_type, :_destroy])
end
My form view partial changed to ::
- if recipe.errors.any?
= render partial: 'errors', locals: { recipe: recipe }
%p
= form.label :name
%br
= form.text_field :name
%p
= form.label :description
%br
= form.text_area :description
%h3 Layers
#layers
= form.fields_for :layers do |layer|
= render 'layer_fields', f: layer
.links
= link_to_add_association 'add layer', form, :layers
%p
= form.submit
and the "layer_fields" partial referenced in the form looks like this ::
.nested-fields
.field
= f.label :glaze_id
%br
= f.collection_select(:glaze_id, Glaze.all, :id, :name, { prompt: "Select Glaze" } )
.field
= f.label :coat_type
%br
= f.text_field :coat_type
= link_to_remove_association 'remove layer', f
Making those changes using the "Cocoon" gem, I was able to accomplish what I needed. Hopefully this helps someone else in the future.
Upvotes: 1