So I have two models:
#app/models/diy.rb
class Diy < Activerecord::Base
#schema id | summary | created_at | updated_at
has_many :steps
end
#app/models/step.rb
class Step < ActiveRecord::Base
# schema id | step_content | photo | created_at | updated_at
belongs_to :diy
end
Is there any way to create a diy database row and associated with it step database rows in the same view?
Closest I've got is:
<%= form_for(@diy) do |f| %>
<%= f.label :summary %><br>
<%= f.text_field :summary %><br>
<%= f.label :steps %><br>
<%= f.text_field :steps %><br>
<%= f.submit %>
<% end %>
but with this code I'm not accessing any columns in step table.
If it helps to solve the problem, with this code i get "Steps" text field which is already filled with "Step::ActiveRecord_Associations_CollectionProxy:0x9613ce0".
class Diy < ActiveRecord::Base
has_many :steps
accepts_nested_attributes_for :steps
end
class Step < ActiveRecord::Base
belongs_to :diy
end
accepts_nested_attributes_for
lets Diy take attributes for Steps:
Diy.create( steps_attributes: [{ step_content: 'Stir it.' }] )
To create the form inputs use fields_for
:
<%= form_for(@diy) do |f| %>
<%= f.label :summary %><br>
<%= f.text_field :summary %><br>
<%- # wrapping it in a fieldset element is optional -%>
<fieldset>
<legend>Steps</legend>
<% f.fields_for(:steps) do |step_fields| %>
<%= step_fields.label :step_content %><br>
<%= step_fields.text_field :step_content %><br>
<% end %>
</fieldset>
<%= f.submit %>
<% end %>
What this does it iterate though @diy.steps
and creates a <textarea name="diy[steps_attributes][][step_content]">
for each. step_fields
is a form builder which is scoped to the particular nested record.
Note that if @diy.steps
is nil like on a new record then there will be no form inputs. To solve that you need to seed the record:
class DiysController
# ...
def new
@diy = Diy.new
@diy.steps.new # creates a new step that the user can fill in.
end
def edit
@diy = Diy.find(params[:id])
@diy.steps.new # creates a new step that the user can fill in.
end
end
To avoid getting a bunch of junk steps you would use the reject_if
option:
class Diy < ActiveRecord::Base
has_many :steps
accepts_nested_attributes_for :steps, reject_if: :all_blank
end
To whitelist the nested attributes in your controller use a array containing the allowed attributes:
def diy_params
params.require(:diy).permit(:summary, steps_attributes: [:step_content])
end