I am building a registration app. There are three models: Participant
, Volunteer_Detail
, and Student_Detail
. Participant
has_one
of the other two models, while they in turn belongs_to
Participant
. I am trying to use one form with fields_for to supply data to Participant
and one of the other models.
I keep getting an error, saying that one of the attributes, intended for Student_Detail
, is not a defined attribute of Participant
.
I have looked at several guides on fields_for
and it seems that there are several ways to define the second model your form is intended for.
The consensus seems to be that it should look like this:
<%= f.fields_for @participant.student_details do |student_detail_field| %>
<%= f.label :nationality, 'Nationality:' %>
<%= student_detail_field.text_field :nationality %>
However it only seems to show my form when I write :student_details as opposed to @participant.student_details.
Here is my form, showing the top section, and the section where fields_for is include(form is trimmed to save space):
<%= f.label :first_name, 'First:' %>
<%= f.text_field :first_name %>
<%= f.fields_for :student_details do |student_detail_field| %>
<%= f.label :nationality, 'Nationality:' %>
<%= student_detail_field.text_field :nationality %>
Here is my Participants controller:
class ParticipantsController < ApplicationController def new @participant= Participant.new end
def new2
@participant= Participant.new
end
def create
@participant = Participant.create(participant_params)
@participant.save
if @participant.save
flash[:success] = "Successfully Registered!"
#email notifes admin of new registration
NotifyMailer.notify_email(@participant).deliver_later
redirect_to '/signup'
end
end
def edit
end
def update
end
def show
end
def index
end
private
def participant_params
params.require(:participant).permit(:first_name, :last_name, :gender, :email, :birthdate, :phone, :street_name, :city, :state, :zip, :nationality, :religion, :need_ride,
:has_spouse, :spouse_name, :english_level, :expectations, :length_of_stay, :exact_length, :volunteer_id, :matched, :returned_home, :participant_id, :participant_id_id)
end
end
Here is the server error:
NoMethodError (undefined method `nationality' for #<Participant:0x000000000d039410>
Did you mean? Rational):
app/controllers/participants_controller.rb:11:in `create'
Rendering C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7.1/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout
Rendering C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7.1/lib/action_dispatch/middleware/templates/rescues/_source.html.erb
Rendered C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7.1/lib/action_dispatch/middleware/templates/rescues/_source.html.erb (3.9ms)
Rendering C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7.1/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb
Rendered C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7.1/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (1.0ms)
Rendering C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb
Rendered C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7.1/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (1.0ms)
Rendered C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/actionpack-5.0.7.1/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (790.6ms)
Looking to see if anyone can help clarify what I'm getting wrong.
Thanks!
There are couple things that probably can help
How to define has_one relationship:
Following rails guide, since Participant has_one student_detail, then the student_detail table has to have field participant_id, also volunteer_detail has to have field participant_id
you can set participant.rb
(model) to accept nested attributes for student_detail or volunteer_detail (since you said provide one form for those tables)
class Participant < ActiveRecord::Base
has_one :student_detail, :dependent => :destroy
accepts_nested_attributes_for :student_detail, :allow_destroy => :true
# that allow_destroy is depend with your software design
has_one :volunteer_detail, :dependent => :destroy
accepts_nested_attributes_for :volunteer_detail, :allow_destroy => :true
end
How to setup participant_params for other tables:
Here is sample of code that define participant params for accept nested atributes:
def participant_params
params.require(:participant).permit(
:first_name, :other_participant_field_name,
student_detail_attributes: [:participant_id, :other_student_field_name],
volunteer_detail_attributes: [:participant_id, :other_volunteer_field_name])
end
end
If you want the content for student record also for volunteer_detail
you can do in your controller (create method), my tip for this try to refactor/redesign to minimize data duplication in your system (student and volunteer)
def create
@participant = Participant.create(participant_params)
@volunteer_detail = @participant.student_detail
# this will pass all the content of student detail to volunteer detail
if @participant.save
flash[:success] = "Successfully Registered!"
end
end
To learn more about accept nested attributes I suggest you learn from railcast 196 although it seem old but you can learn the concept