Rails has_many :through nested form
has-many-through, nested-forms, ruby-on-rails
Solution
Ok, this little bugger of a question stumped me for a few hours, so I'm going to post my working solution on here in hopes it shaves some time for peeps. This is for Rails 4.0 and Ruby 2.0. This also overcame a "symbol to integer conversion" issue I had.
Models:
class Patient < ActiveRecord::Base
has_many :appointments
has_many :physicians, through: :appointments
accepts_nested_attributes_for :appointments
end
class Appointment < ActiveRecord::Base
belongs_to :physician
belongs_to :patient
accepts_nested_attributes_for :physician
end
class Physician < ActiveRecord::Base
has_many :appointments
has_many :patients, through: :appointments
end
Controller:
# patients_controller.rb
def new
@patient= Patient.new
@appointments = @patient.appointments.build
@physician = @appointments.build_physician
end
def create
Patient.new(patient_params)
end
def patient_params
params.require(:patient).permit(:id, appointments_attributes: [:id, :appointment_time, physician_attributes: [:id ] )
end
View
<% form_for(@patient) do |patient_form| %>
<%= patient_form.error_messages %>
<p>
<%= patient_form.label :name, "Patient Name" %>
<%= patient_form.text_field :name %>
</p>
<% patient_form.fields_for :appointments do |appointment_form| %>
<p>
<%= appointment_form.label :appointment_date, "Appointment Date" %>
<%= appointment_form.date_field :appointment_date %>
</p>
<% appointment_form.fields_for :physician do |physician_form| %>
<p>
<%= physician_form.label :name, "Physician Name" %>
<%= physician_form.text_field :name %>
</p>
<% end %>
<% end %>
<p>
<%= patient_form.submit 'Create' %>
</p>
<% end %>
<%= link_to 'Back', patients_path %>
Problem
I have just jumped into `has_many :through` association. I'm trying to implement the ability to save data for all 3 tables (`Physician`, `Patient` and association table) through a single form. My migrations: ``` class CreatePhysicians < ActiveRecord::Migration def self.up create_table :physicians do |t| t.string :name t.timestamps end end end class CreatePatients < ActiveRecord::Migration def self.up create_table :patients do |t| t.string :name t.timestamps end end end class CreateAppointments < ActiveRecord::Migration def self.up create_table :appointments do |t| t.integer :physician_id t.integer :patient_id t.date :appointment_date t.timestamps end end end ``` My models: ``` class Patient < ActiveRecord::Base has_many :appointments has_many :physicians, :through => :appointments accepts_nested_attributes_for :appointments accepts_nested_attributes_for :physicians end class Physician < ActiveRecord::Base has_many :appointments has_many :patients, :through => :appointments accepts_nested_attributes_for :patients accepts_nested_attributes_for :appointments end class Appointment < ActiveRecord::Base belongs_to :physician belongs_to :patient end ``` My controller: ``` def new @patient = Patient.new @patient.physicians.build @patient.appointments.build end ``` My view (`new.html.rb`): ``` <% form_for(@patient) do |patient_form| %> <%= patient_form.error_messages %> <p> <%= patient_form.label :name, "Patient Name" %> <%= patient_form.text_field :name %> </p> <% patient_form.fields_for :physicians do |physician_form| %> <p> <%= physician_form.label :name, "Physician Name" %> <%= physician_form.text_field :name %> </p> <% end %> <p> <%= patient_form.submit 'Create' %> </p> <% end %> <%= link_to 'Back', patients_path %> ``` I'm able to create a new `Patient`, `Physician` and associated record for an `Appointment`, but now I want to have field for `appointment_date` too in form. Where should I place fields for `Appointment`s and what changes are required in my controller? I tried googling and tried this, but got stuck in some or other error implementing it.