Using Rails models with accepts_nested_attributes_for - ruby-on-rails

I'm writing a simple Rails model called Person that has_many :phone_numbers and I'm trying to save the phone numbers in a complex form without manually writing setter methods. accepts_nested_attributes_for should do what I want but I'm having trouble getting it to work. Here's the code I have so far:
Migration
class CreatePeople < ActiveRecord::Migration
def self.up
create_table :people do |t|
t.string :first_name
t.string :last_name
t.integer :address_id
t.string :email
t.timestamps
end
end
def self.down
drop_table :people
end
end
class CreatePhoneNumbers < ActiveRecord::Migration
def self.up
create_table :phone_numbers do |t|
t.string :number, :limit => 10
t.string :extension, :limit => 5
t.string :description, :null => false
t.integer :telephone_id
t.string :telephone_type
t.timestamps
end
end
def self.down
drop_table :phone_numbers
end
end
Models
class Person < ActiveRecord::Base
has_one :address, :as => :addressable, :dependent => :destroy
has_many :phone_numbers,
:as => :telephone,
:dependent => :destroy
accepts_nested_attributes_for :phone_numbers
attr_protected :id
validates_presence_of :first_name, :last_name, :email
end
class PhoneNumber < ActiveRecord::Base
attr_protected :id
belongs_to :telephone, :polymorphic => true
end
View
<% form_for #person, :builder => CustomFormBuilder do |f| %>
<%= f.error_messages %>
<%= f.text_field :first_name %>
<%= f.text_field :last_name %>
<% fields_for "person[address]", #person.address, :builder => CustomFormBuilder do |ff| %>
<%= ff.text_field :address_1 %>
<%= ff.text_field :address_2 %>
<%= ff.text_field :city %>
<%= ff.text_field :state %>
<%= ff.text_field :zip %>
<% end %>
<h2>Phone Numbers</h2>
<% #person.phone_numbers.each do |phone_number| %>
<% fields_for "person[phone_numbers][]", phone_number, :builder => CustomFormBuilder do |ff| %>
<%= ff.text_field :description %>
<%= ff.text_field :number %>
<%= ff.text_field :extension %>
<% end %>
<% end %>
<%= f.text_field :email %>
<%= f.submit 'Create' %>
<% end %>
Controller
def new
#person = Person.new
#person.build_address
#person.phone_numbers.build
respond_to { |format| format.html }
end
def create
#person = Person.new(params[:person])
respond_to do |format|
if #person.save
flash[:notice] = "#{#person.name} was successfully created."
format.html { redirect_to(#person) }
else
format.html { render :action => 'new' }
end
end
end
I have verified that a phone_numbers= method is being created, but the post still causes:
PhoneNumber(#69088460) expected, got HashWithIndifferentAccess(#32603050)
RAILS_ROOT: H:/projects/test_project
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/associations/association_proxy.rb:263:in `raise_on_type_mismatch'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/associations/association_collection.rb:319:in `replace'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/associations/association_collection.rb:319:in `each'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/associations/association_collection.rb:319:in `replace'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/associations.rb:1290:in `phone_numbers='
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/base.rb:2740:in `send'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/base.rb:2740:in `attributes='
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/base.rb:2736:in `each'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/base.rb:2736:in `attributes='
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.3/lib/active_record/base.rb:2434:in `initialize'
H:/projects/salesguide/app/controllers/accounts_controller.rb:46:in `new'
H:/projects/test_project/app/controllers/accounts_controller.rb:46:in `create'
I can get this to work by manually writing the phone_numbers= method, but this would cause a tremendous duplication of effort, I would much rather learn how to do this right. Can anybody see what I'm doing wrong?

You're forgetting the to call fields_for as a method on the person form. Otherwise you're not actually using fields_for in a accept_nested_attributes_for context. Michael's solution tries to trick Rails into treating the submission as a properly defined accepts_nested_attributes_for form.
The correct syntax for what you are trying to do is:
parent_form_object.fields_for id, object_containing_values, {form_for options}, &block
You'll find the code looks cleaner and simpler to debug if you provide a symbol as id, containing the association name of the child model as defined in your Person model.
Also, the each block you're using might cause problems if #person.phone_numbers is empty. You can ensure that there is at least one set of Phone Number fields with a line similar to the one I used with
<% #phs = #person.phone_numbers.empty? ? #person.phone_numbers.build : #person.phone_numbers %>
With all corrections, this code will do what you want it to.
View
<% form_for #person, :builder => CustomFormBuilder do |f| %>
<%= f.error_messages %>
<%= f.text_field :first_name %>
<%= f.text_field :last_name %>
<% f.fields_for :address, #person.address, :builder => CustomFormBuilder do |address_form| %>
<%= address_form.text_field :address_1 %>
<%= address_form.text_field :address_2 %>
<%= address_form.text_field :city %>
<%= address_form.text_field :state %>
<%= address_form.text_field :zip %>
<% end %>
<h2>Phone Numbers</h2>
<% #phs = #person.phone_numbers.empty? ? #person.phone_numbers.build : #person.phone_numbers %>
<% f.fields_for :phone_numbers, #phs, :builder => CustomFormBuilder do |phone_number_form| %>
<%= phone_number_form.text_field :description %>
<%= phone_number_form.text_field :number %>
<%= phone_number_form.text_field :extension %>
<% end %>
<%= f.text_field :email %>
<%= f.submit 'Create' %>
<% end %>
You might find it useful to check out the complex-form-examples repository on github for a working example. It also comes with code to dynamically add new entries for :has_many relationships from the view/form.

I was playing around with accepts_nested_attributes_for yesterday when trying to figure out Rails form with three models and namespace. I needed to setup the form slightly differently, try using: person[phone_numbers_attributes][]

Related

Where is my "unpermitted parameter: :passenger" Rails error coming from?

I am building a flight booking app with Rails that lets you select airports, date and number of passengers. Once you select the airports and dates, it gives you radio buttons to select which flight you want and, once you click submit, you are taken to a booking confirmation page where you are asked to provide passenger info.
The confirmation page(bookings#new) has a nested form to include passengers in the booking object. To do this, I have first set the following models and associations:
class Passenger < ApplicationRecord
belongs_to :booking
end
class Booking < ApplicationRecord
belongs_to :flight
has_many :passengers
accepts_nested_attributes_for :passengers
end
And the relevant migrations that result in the following schema tables:
create_table "bookings", force: :cascade do |t|
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "flight_id"
t.integer "passenger_id"
end
create_table "passengers", force: :cascade do |t|
t.string "name"
t.string "email"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.integer "booking_id"
t.index ["booking_id"], name: "index_passengers_on_booking_id"
end
From what I understand, the flow goes like this:
User selects flight -> User submits flight, goes to Booking#new through the #new method on my controller:
class BookingsController < ApplicationController
def new
#booking = Booking.new
#flight = Flight.find(params[:flight_id])
params[:passengers_number].to_i.times do #params passed from select flight page
#booking.passengers.build
end
end
Then, the form I built takes over on new.html.erb:
<%= form_with model: #booking, url: bookings_path do |f| %>
<%= f.hidden_field :flight_id, value: #flight.id %>
<% #booking.passengers.each_with_index do |passenger, index| %>
<%= f.fields_for passenger, index: index do |form| %>
<h4><%= "Passenger #{index+1}"%> <br> </h4>
<%= form.label :name, "Full name:" %>
<%= form.text_field :name %>
<%= form.label :email, "Email:" %>
<%= form.email_field :email %>
<% end %>
<% end %>
<%= f.submit "Confirm details"%>
<% end %>
I fill it in with names and emails, click 'Confirm details' and I get this error on my terminal:
Unpermitted parameter: :passenger
Why? I have set accepts_nested_attributes_for :passengers on my Booking model, my booking_params method is:
def booking_params
params.require(:booking).permit(:flight_id,
:passengers_attributes => [:name, :email, :passenger_id, :created_at, :updated_at])
end
and my #create method is:
def create
#booking = Booking.new(booking_params)
respond_to do |format|
if #booking.save
format.html { redirect_to #booking, notice: "booking was successfully created." }
format.json { render :show, status: :created, location: #booking }
else
format.html { redirect_to root_path, alert: "booking failed, #{#booking.errors.full_messages.first}" , status: :unprocessable_entity }
format.json { render json: #booking.errors, status: :unprocessable_entity }
end
end
end
Is there something I am not permitting properly? Note that if I set booking_params as params.require(:booking).permit! it gives me an unknown attribute 'passenger' for Booking error. But I have defined associations and database on passenger and booking, at least to my knowledge.
Thanks in advance
Edit: The server log that generates the error is:
Started POST "/bookings" for ::1 at 2021-08-27 17:52:17 +0300
Processing by BookingsController#create as HTML
Parameters: {"authenticity_token"=>"[FILTERED]", "booking"=>{"flight_id"=>"5", "passenger"=>{"0"=>{"name"=>"Jason Smason", "email"=>"jason#ymail.com"}, "1"=>{"name"=>"Joe Smith", "email"=>"Joe#smith.com"}}}, "commit"=>"Confirm details"}
Unpermitted parameter: :passenger
Edit2: I followed PCurell's advice and changed my fields_for to <%= f.fields_for :passengers, passenger, index: index do |form| %> and my booking params to :passenger => [:name, :email, :passenger_id, :created_at, :updated_at])
That generated a different error: Unpermitted parameter: passengers_attributes'. So I changed my controller's booking_params` to:
def booking_params
params.require(:booking).permit(:flight_id,
:passengers_attributes => [:name, :email, :passenger_id, :created_at, :updated_at],
:passenger => [:name, :email, :passenger_id, :created_at, :updated_at])
end
With that, I successfully managed to create a booking with 2 passengers. However, the passengers are blank; their name and email are nil. The log says:
Parameters: {"authenticity_token"=>"[FILTERED]", "booking"=>{"flight_id"=>"1", "passengers_attributes"=>{"0"=>{"0"=>{"name"=>"John Smith", "email"=>"John#smith.com"}}, "1"=>{"1"=>{"name"=>"Burger King", "email"=>"bk#bk.com"}}}}, "commit"=>"Confirm details"}
Unpermitted parameter: :0
Unpermitted parameter: :1
I might be able to hardcode :0 and :1 to pass, but surely that's not the Rails way. Is there a way to dynamically let them in? Or am I doing the whole thing wrong?
Your usage of fields_for is incorrect. When you look at the example in the guide you will notice that there is no need to wrap it with an .each if used for a collection.
10.2 Nested Forms
The following form allows a user to create a Person and its
associated addresses.
<%= form_with model: #person do |form| %>
Addresses:
<ul>
<%= form.fields_for :addresses do |addresses_form| %>
<li>
<%= addresses_form.label :kind %>
<%= addresses_form.text_field :kind %>
<%= addresses_form.label :street %>
<%= addresses_form.text_field :street %>
...
</li>
<% end %>
</ul>
<% end %>
When an association accepts nested attributes fields_for renders its block once for every element of the association. In particular,
if a person has no addresses it renders nothing. A common pattern is
for the controller to build one or more empty children so that at
least one set of fields is shown to the user. The example below would
result in 2 sets of address fields being rendered on the new person
form.
def new
#person = Person.new
2.times { #person.addresses.build }
end
When applying this to your code, removing the .each wrapper and changing passenger into :passengers should do the trick. You can access the index through the FormBuilder instance (form) passed to the fields_for block.
<%= form_with model: #booking, url: bookings_path do |f| %>
<%= f.hidden_field :flight_id, value: #flight.id %>
<%= f.fields_for :passengers do |form| %>
<h4>Passenger <%= form.index + 1 %></h4>
<%= form.label :name, "Full name:" %>
<%= form.text_field :name %>
<%= form.label :email, "Email:" %>
<%= form.email_field :email %>
<% end %>
<%= f.submit "Confirm details"%>
<% end %>
As #Rockwell Rice mentioned in his comment:
The problem here is that you are permitting the wrong param.
def booking_params
params.require(:booking).permit(:flight_id,
:passenger => [:name, :email, :passenger_id, :created_at, :updated_at])
end
Should work.
Although you might encounter another error.
I think that you are constructing your fields_for wrong.
This should be what you are looking for (and you will not have to change the booking_params)
<%= form_with model: #booking, url: bookings_path do |f| %>
<%= f.hidden_field :flight_id, value: #flight.id %>
<% #booking.passengers.each_with_index do |passenger, index| %>
<%= f.fields_for :passengers, passenger, index: index do |form| %>
<h4><%= "Passenger #{index+1}"%> <br> </h4>
<%= form.label :name, "Full name:" %>
<%= form.text_field :name %>
<%= form.label :email, "Email:" %>
<%= form.email_field :email %>
<% end %>
<% end %>
<%= f.submit "Confirm details"%>
<% end %>
The above should work.
If you don't care too much about the index this would work as well:
<%= form_with model: #booking, url: bookings_path do |f| %>
<%= f.hidden_field :flight_id, value: #flight.id %>
<%= f.fields_for #booking.passengers do |form| %>
<%= form.label :name, "Full name:" %>
<%= form.text_field :name %>
<%= form.label :email, "Email:" %>
<%= form.email_field :email %>
<% end %>
<%= f.submit "Confirm details"%>
<% end %>

Create multiple new records from checkboxes in form using nested attributes in Rails

I'm trying to come up with a contact form that creates a contact record and potentially multiple location records, if multiple locations are checked in a list of checkboxes. I thought of having all location records created and then destroyed, if they aren't checked. I don't think that's optimal though.
I'm using many to many relationships in the models.
This is what they look like at the moment:
contact.rb
class Contact < ApplicationRecord
has_many :contact_locations, dependent: :destroy
has_many :locations, through: :contact_locations
accepts_nested_attributes_for :contact_locations, allow_destroy: true, reject_if: :empty_location?
private
def empty_location?(att)
att['location_id'].blank?
end
end
location.rb
class Location < ApplicationRecord
has_many :locations, dependent: :destroy
has_many :contacts, :through => :contact_locations
has_many :contact_locations
end
contact_location.rb
class ContactLocation < ApplicationRecord
belongs_to :location
belongs_to :contact
end
contacts_controller.rb
def new
#contact = Contact.new
#locations = Location.all
4.times {#contact.contact_locations.new}
end
private
def contact_params
params.require(:contact).permit(:name, :phone, ..., contact_locations_attributes: [:location_ids])
end
new.html.rb
<%= form_with model: #contact do |f| %>
...
<%= #locations.each do |location| %>
<%= f.fields_for :contact_locations do |l| %>
<%= l.check_box :location_id, {}, location.id, nil %><%= l.label location.name %>
<% end %>
<% end %>
...
<% end %>
Does anyone how to make it work properly?
I'm working on Ruby 2.5.1 and Rails 5.2.1.
Thanks a lot.
I think your solution is the form objects pattern.
You can have something like this:
<%= form_for #user do |f| %>
<%= f.email_field :email %>
<%= f.fields_for #user.build_location do |g| %>
<%= g.text_field :country %>
<% end %>
<% end%>
And convert it in something more readable that permits you to instance the locations inside the registration object, checking the value of the checkboxes.
<%= form_for #registration do |f| %>
<%= f.label :email %>
<%= f.email_field :email %>
<%= f.input :password %>
<%= f.text_field :password %>
<%= f.input :country %>
<%= f.text_field :country %>
<%= f.input :city %>
<%= f.text_field :city %>
<%= f.button :submit, 'Create account' %>
<% end %>
Here you will find how to apply the pattern: https://revs.runtime-revolution.com/saving-multiple-models-with-form-objects-and-transactions-2c26f37f7b9a
I ended up making it work with Kirti's suggestion on the following question:
Rails Nested attributes with check_box loop
It turns out I needed to make a small adjustment in my form's fields_for tag.
Thanks a lot the help!

Rails5 - Update join table with has_many :through : using fields_for

I have a trouble to update my join table course_students.
When I create a new student, I want to select a course from dropdown list(from two courses Course1 and Course2 which already saved in course table) and update course_students. And I want my couse_students table to be something like this.
id | student_id | course_id | created_at | updated_at
----+------------+-----------+----------------------------+----------------------------
1 | 1 | 1 | 2017-08-23 16:41:57.228094 | 2017-08-23 16:41:57.228094
Thanks to http://railscasts.com/episodes/17-habtm-checkboxes-revised?view=asciicast, I somehow found out the following code works for radio_button_tag. But there is an error wrong number of arguments when I change radio_button_tag to select_tag.
Also, I am not sure if this is the correct way because the information seems bit old. After some google search, I often found that people use field_for in new.html.erb, so I tried but I could not update course_students table.
In the future, I would like to add other columns like teacher, date_from, class_room, and something like that in course_students table.
I would really appreciate your help.
・models
class Student < ApplicationRecord
has_many :course_students
has_many :courses, :through => :course_students
accepts_nested_attributes_for :course_students
end
class Course < ApplicationRecord
has_many :course_students
has_many :students, :through => :course_students
end
class CourseStudent < ApplicationRecord
belongs_to :student
belongs_to :course
end
・migrations
class CreateStudents < ActiveRecord::Migration[5.1]
def change
create_table :students do |t|
t.string :first_name
t.string :middle_name
t.string :last_name
t.timestamps
end
end
end
class CreateCourses < ActiveRecord::Migration[5.1]
def change
create_table :courses do |t|
t.string :name
t.timestamps
end
end
end
class CreateCourseStudents < ActiveRecord::Migration[5.1]
def change
create_table :course_students do |t|
t.integer :student_id
t.integer :course_id
t.timestamps
end
end
end
・course table
id | name | created_at | updated_at
----+--------------+----------------------------+----------------------------
1 | Course1 | 2017-08-22 20:03:46.226893 | 2017-08-22 20:03:46.226893
2 | Course2 | 2017-08-22 20:03:46.228765 | 2017-08-22 20:03:46.228765
・student.controller, strong params.
def student_params
params.require(:student).permit(:first_name, :middle_name, :last_name, course_ids: [], date_froms: [] )
end
・new.html.erb
<h1>Create new student</h1>
<%= form_for(#student) do |f| %>
<%= f.label :first_name %>
<%= f.text_field :first_name %>
<%= f.label :middle_name %>
<%= f.text_field :middle_name %>
<%= f.label :last_name %>
<%= f.text_field :last_name %>
<%= Course.all.each do |course| %>
<%= radio_button_tag "student[course_ids][]", course.id, #student.course_ids.include?(course.id), id: dom_id(course)%>
<%= label_tag dom_id(course), course.name %>
<% end %>
<%= f.submit "Create new student", class: "btn btn-primary" %>
<% end %>
Use nested_form_for instead of form_for and for course_students use field_for that nested form helper provide. https://github.com/ryanb/nested_form
<h1>Create new student</h1>
<%= nested_form_for(#student) do |f| %>
<%= f.label :first_name %>
<%= f.text_field :first_name %>
<%= f.label :middle_name %>
<%= f.text_field :middle_name %>
<%= f.label :last_name %>
<%= f.text_field :last_name %>
<%= f.fields_for :course_students do |ff| %>
<%= ff.hidden_field :student_id, value: #student.id %>
<%= ff.collection_select :course_id, Course.all, :id, :name %>
<% end %>
<%= f.submit "Create new student", class: "btn btn-primary" %>
<% end %>
you needs to permit course_students params in controller like this:
def student_params
params.require(:student).permit(:first_name, :middle_name, :last_name, course_students_attributes: [ :course_id, :student_id] )
end
Found out that the following code worked!
students_controller
def new
#student = Student.new
#student.course_students.build
end
private
def student_params
params.require(:student).permit(:first_name, :middle_name, :last_name, course_students_attributes: [ :course_id, :student_id] )
end
new.html.erb
<%= f.fields_for :course_students do |ff| %>
<%= ff.hidden_field :student_id, value: #student.id %>
<%= ff.collection_select :course_id, Course.all, :id, :name %>
<% end %>
Thanks!

RoR multi nesting with polymorphic associations + devise

I have polymorphic associations with different models that I want to save upon submitting the registration form using devise. i.e:
User
Company + ContactInfo
Employee + ContactInfo
I understand that nesting forms is not recommended but What would be the best way to achieve this?
Thanks
models:
class User < ActiveRecord::Base
belongs_to :company
accepts_nested_attributes_for :company
end
class Company < ActiveRecord::Base
has_many :employees
has_one :contact_info, as: :contactable
accepts_nested_attributes_for :contact_info
end
class Employee < ActiveRecord::Base
belongs_to :company
has_one :contact_info, as: :contactable
accepts_nested_attributes_for :contact_info
end
class ContactInfo < ActiveRecord::Base
belongs_to :imageable, polymorphic: true
end
migrations:
class CreateCompanies < ActiveRecord::Migration
def change
create_table :companies do |t|
t.string :name
t.references :contact_info, index: true
t.string :website
t.timestamps null: false
end
add_foreign_key :companies, :contact_infos
end
end
class CreateEmployees < ActiveRecord::Migration
def change
create_table :employees do |t|
t.string :first_name
t.string :last_name
t.references :company, index: true
t.references :contact_info, index: true
t.string :job_title
t.timestamps null: false
end
add_foreign_key :employees, :contact_infos
end
end
class CreateContactInfos < ActiveRecord::Migration
def change
create_table :contact_infos do |t|
t.string :email
t.string :phone
t.string :mobile
t.string :contactable_type
t.integer :contactable_id
t.timestamps null: false
end
end
end
registration controller:
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up).push(:name, :email, :password, company_attributes: [ :id, :name, :website, :company_type, :number_of_employees, contact_info_attributes: [ :id, :email, :phone, :mobile]])
end
devise's new registration:
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :role => 'form'}) do |f| %>
<%= devise_error_messages! %>
<%= hidden_field_tag 'plan', params[:plan] %>
<% resource.build_company %>
<%= f.fields_for :company do |f| %>
<%= render "companies/fields", f: f %>
<% end %>
<% resource.company.build_contact_info %>
<%= f.fields_for :contact_info do |f| %>
<%= render "contact_infos/fields", f: f %>
<% end %>
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name, :autofocus => true, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
</div>
<%= f.submit 'Sign up', :class => 'button right' %>
<% end %>
Console:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"Nb6Na8P93s1dYvlDIQuiG11IoDeSzSylH4BCN8Tm7ipxCsbsdiWjDx5tJpijwldkjK4pPfjuwROnEvybYS7UIQ==", "plan"=>"free", "user"=>{"company_attributes"=>{"name"=>"Company Name", "website"=>"company website", "company_type"=>"company type", "number_of_employees"=>"121"}, "contact_info"=>{"email"=>"company#email.com", "phone"=>"1234", "mobile"=>"1234"}, "name"=>"user_name", "email"=>"user_email#email.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Sign up"}
Unpermitted parameter: contact_info
only User and company params are saving well. I was trying to get the devise_parameter_sanitizer to work with nesting contact_info in company first without trying the same with employee just yet, any idea what I'm doing wrong or any tips if im on the right track?
Thanks!
Update:
However contact_info params are permitted if I nest the contact_info form fields within the company form fields like so:
<% resource.build_company %>
<%= f.fields_for :company do |f| %>
<%= render "companies/fields", f: f %>
<% resource.company.build_contact_info %>
<%= f.fields_for :contact_info do |cf| %>
<%= render "contact_infos/fields", f: cf %>
<% end %>
<% end %>
the question is, is that good practice?
This is a guess - but your contact_info for the company isn't nested inside the company section. Try something like this (note, not tested, probably buggy)
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :role => 'form'}) do |f| %>
<%= devise_error_messages! %>
<%= hidden_field_tag 'plan', params[:plan] %>
<% resource.build_company %>
<%= f.fields_for :company do |f| %>
<%= render "companies/fields", f: f %>
<%# this is now nested inside the company-fields %>
<% resource.company.build_contact_info %>
<%= f.fields_for :contact_info do |f| %>
<%= render "contact_infos/fields", f: f %>
<% end %>
<% end %>
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name, :autofocus => true, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
</div>
<%= f.submit 'Sign up', :class => 'button right' %>

Nested model form fields not appearing

I have a has_many belongs_to relationship between Job and Address
class Job < ActiveRecord::Base
has_many :addresses
accepts_nested_attributes_for :addresses
end
class Address < ActiveRecord::Base
belongs_to :job
end
Inside the Job form I inserted the proper fields for text:
<%= f.fields_for :addresses do |address| %>
<%= address.label :label, "Label" %>
<%= address.text_field :label %>
<%= address.label :addy, "Address" %>
<%= address.text_field :addy %>
<%= address.label :apt, "Apt/Suite/etc" %>
<%= address.text_field :apt %>
<%= address.label :city, "City" %>
<%= address.text_field :city %>
<%= address.label :state, "State" %>
<%= address.text_field :state %>
<%= address.label :zip, "Zip code" %>
<%= address.text_field :zip %>
<% end %>
But the fields don't appear. Am I missing something?
EDIT: Added the create action from the Jobs controller
def create
#job = Job.new(job_params)
#job.addresses.build
#job.user_id = current_user.id
if #job.save
render 'show'
else
render 'new'
end
end
What does your Controller look like? Are you building the addresses for the Job?
For example, you need to do something like this in your new action in your controller:
def new
#job = Job.new
#job.addresses.build
end
I hope this helps.

Resources