How do I make nested_attributes work in Rails3? - ruby-on-rails

Here's my user model:
class User < ActiveRecord::Base
has_one :teacher, :dependent => :destroy
accepts_nested_attributes_for :teacher, :allow_destroy => true
attr_accessible :email, :password, :password_confirmation, :remember_me, :teacher_attributes
end
Here's my teacher model:
class Teacher < ActiveRecord::Base
belongs_to :user
attr_accessible :user_id, :first_name, :last_name
validates_presence_of :user_id, :first_name, :last_name
end
Here's my form:
<%= form_for(#user, :url => registration_path(:user)) do |user| %>
<%= user.text_field :email %>
<%= user.text_field :password %>
<%= user.text_field :password_confirmation %>
<%= user.fields_for resource.build_teacher do |t| %>
<%= t.text_field :first_name %>
<%= t.text_field :last_name %>
<%= t.text_field :phone %>
<% end %>
<%= user.submit 'Confirm' %>
<% end %>
Except that this thing won't "accept nested attributes"
My development log says:
WARNING: Can't mass-assign protected attributes: teacher
I don't know if it's related, but the form isn't generating fields inside a teacher_attributes array or anything - it's inside teacher. I'm guessing that's where my problem is, but I don't how to make it put the fields inside it. Please help.
Thanks!

Try these things:
At top of view:
<% #user.build_teacher if #user.teacher.nil? %>
For the fields for:
<%= user.fields_for :teacher do |t| %>
Also, personally, I like naming the block parameters in forms (the part |user| and |t|) as |form| (because when you're having a long day, and you see user down in the view and not form, it can confuse you!)

Related

Auxiliary parameter in a form

I'm trying to manage invitations to an event with a "participation" model. I'd like that, when I invite a user, i could insert his name in the form, instead of user_id.
user.rb
class User < ActiveRecord::Base
attr_accessible :id, :name
has_many :participations
end
participation.rb
class Participation < ActiveRecord::Base
attr_accessible :event_id, :user_id
belongs_to :event
belongs_to :user
end
views/participations/new.html.erb
<%= form_for(#participation) do |f| %>
<%= f.hidden_field :event_id, value: #event.id %>
<%= f.label :user_id, 'User Id' %>
<%= f.number_field :user_id %>
<%= f.submit 'Invite' %>
<% end %>
How can i do?
Try by this:
<%= form_for(#participation) do |f| %>
<%= f.hidden_field :event_id, value: #event.id %>
<%= f.label :user_id, 'User Id' %>
<%=f.collection_select :user_id,User.all,:id,:name,:label => "User" ,:include_blank => false%>
<%= f.submit 'Invite' %>
<% end %>
You may turn include_blank to true or false as you wish to always have a user or not.
Feel free to ask for more if this doesn't solve your problem.

Nested form undefined method `model_name'

I have nested forms dealing with 3 models. Job, Employer, User
The form on the jobs controller needs to create a job, employer and user.
The Job and Employer forms are working correctly, however when I add the User nested form I get the error "undefined method `model_name' for NilClass:Class"
I'm completely confused as to why.
Here is my code:
Job Model
attr_accessible :category, :employer_id, :employer_attributes, :user_attributes
belongs_to :employer
accepts_nested_attributes_for :employer, :user
has_many :applications
has_many :users, :through => :applications
Employer model
attr_accessible :companyname, :email, :logo, :password, :url
has_many :jobs
belongs_to :user
User Model
attr_accessible :admin, :cv, :name, :password, :website, :password_confirmation
has_many :applications
has_many :jobs, :through => :applications
has_one :employer
_form.html.erb
<%= form_for(#job) do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.fields_for :employer do |builder| %>
<%= builder.label :companyname, "Company Name" %>
<%= builder.text_field :companyname %>
<% end %>
<%= f.fields_for :user do |builder| %>
<%= builder.label :email, "Email" %>
<%= builder.text_field :email %>
<%= builder.label :password, "Password" %>
<%= builder.text_field :password %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Job Controller
def new
#job = Job.new
#job.employer = #job.build_employer
#job.user = #job.build_user
To doesn't look like your Job model has a user method. You may need to add
belongs_to :user

How to build a devise nested resource during registration?

During registration of a new user with Devise, I need to create a new Family object link to this new user at the same time (the user being the head of the family).
My family model:
belongs_to user
My user model:
attr_accessible :name, :email, :password, :password_confirmation, :remember_me, :family
has_one :family
accepts_nested_attributes_for :family
In devise/registration/new.html.erb
<%= simple_form_for([resource, Family.new], :as => resource_name, :url => registration_path(resource_name), :html => {:class => 'form-vertical' }) do |f| %>
<%= f.error_notification %>
<%= display_base_errors resource %>
<%= f.input :name, :autofocus => true %>
<%= f.input :email, :required => true %>
<%= f.input :password, :required => true %>
<%= f.input :password_confirmation, :required => true %>
<% f.fields_for :family do |family_form| %>
<p><%= family_form.label :name %></p>
<p><%= family_form.text_field :name %></p>
<% end %>
<%= f.button :submit, 'OK', :class => 'btn-primary' %>
<% end %>
But this is not working, I find a couple of question like this but I did not manage to fix that.
Any idea ?
UPDATE 1
I got the following error:
undefined method `email' for #<Family:0x007f892a12c310>
Family is a model that do not have any email, just a name. I just need to be able to create a new Family object with a name when creating a new user (and link it to the user as well).
UPDATE 2
I have added resource.build_family in my registrations controller. The family object is correctly created and associated to the user (I can display <%= resource.family %> in new.html.erb for debugging), but still no form displayed for the family.
You need the equal sign in the <%=fields_for
<%= f.fields_for :family do |family_form| %>
<p><%= family_form.label :name %></p>
<p><%= family_form.text_field :name %></p>
<% end %>
And in your user model you need to make the :family_attribues accessible and not :family
attr_accessible :name, :email, :password, :password_confirmation, :remember_me, :family_attributes
has_one :family
accepts_nested_attributes_for :family
If you're getting undefined method 'email' for #<Model:0x007f892a12c310>:
You need to overwrite Devise::RegistrationsController as described in the docs: https://github.com/heartcombo/devise#configuring-controllers. E.g.
class Users::RegistrationsController < Devise::RegistrationsController
def new
super do |resource|
resource.build_<model>
end
end
end
And you must only specify resource in form_for: simple_form_for(resource, ... instead of simple_form_for([resource, Model.new], ...

rails - polymorphic association - one-to-one - Form is submiting nested fields with wrong name

I have User, which can be one of three types: Admin, Student, Teacher. Everyone has other attributes. I am trying polymorphic association one-to-one like this:
User
class User < ActiveRecord::Base
belongs_to :identity, :polymorphic => true
accepts_nested_attributes_for :identity, :allow_destroy => true
attr_accessible :email, :login, :remember_token,
:password_confirmation, :password, :role
end
Student
class Student < ActiveRecord::Base
attr_accessible :field
has_one :user, :as => :identity
end
Controller
def new
#user = User.new
end
def create
#user = User.new(params[:user]) # It fails here.
#user.identita.build
...
end
View
<%= form_for(#user) do |f| %>
<%= f.label :login %><br />
<%= f.text_field :login %>
<%= f.fields_for [:identity, Student.new] do |i| %>
<%= i.label :field %><br />
<%= i.textfield_select :field %>
<% end %>
<% end %>
When I submit this view (more complex, but this is the core), it sends hash like this:
{"utf8"=>"✓",
"authenticity_token"=>"...",
"user"=>{"login"=>"...",
"student"=> {"field"=>"..."}
}
So it fails on marked line in controller with:
ActiveModel::MassAssignmentSecurity::Error in UsersController#create
Can't mass-assign protected attributes: student
What am I doing wrong? Something like :as=>"student" or twisting the realationship?
Firstly, fix:
<%= f.fields_for [:identity, Student.new] do |i| %>
to:
<%= f.fields_for :identity, Student.new do |i| %>
Secondly, you are trying to use accepts_nested_attributes_for on a belongs_to relationship. This is not supported behavior AFAIK. Perhaps try moving that to the Student model:
class Student < ActiveRecord::Base
attr_accessible :field
has_one :user, :as => :identity
accepts_nested_attributes_for :user, :allow_destroy => true
end
and make the view like this:
<%= form_for(Student.new) do |i| %>
<%= i.fields_for :user, #user do |f| %>
<%= f.label :login %><br />
<%= f.text_field :login %>
<% end %>
<%= i.label :field %><br />
<%= i.textfield_select :field %>
<% end %>
From documentation of attr_accessible
attr_accessible will only set attributes in this list, to assign to
the rest of attributes you can use direct writer methods.
So once you've used attr_accessible, another attributes automatically will become a protected ones.

Edit form load error using Formtastic, STI, Polymorphic & ActiveAdmin

I am new to rails and using a combination of formtastic, activeadmin,sti and polymorphic associations to build a form
When I I can create a nested form with the address parent with no problem, but when i introduce STI and attempt to build_origin_address instead of build_address, that is when I get the error below when loading the edit view
NameError in Admin/leads#edit
Showing .../app/views/admin/leads/_form.erb where line #3 raised:
uninitialized constant Lead::OriginAddress
Models:
class Address < ActiveRecord::Base
belongs_to :addressable, :polymorphic => true
belongs_to :lead
validates :line1, :presence => true, :length => {:minimum => 2}
attr_accessible :line1, :line2, :city, :state, :zip, :country
end
class OriginAddress < Address
end
class DestinationAddress < Address
end
class Lead < ActiveRecord::Base
has_one :origin_address, :dependent => :destroy, :as => :addressable
accepts_nested_attributes_for :origin_address, :allow_destroy => true
end
partial used in edit view:
<%= semantic_form_for [:admin, #lead] do |f| %>
<% #lead.build_origin_address unless #lead.origin_address %>
<%= f.inputs :name => "Lead Info" do %>
<%= f.input :first_name %>
<%= f.input :last_name %>
<% end %>
<%= f.semantic_fields_for :origin_address do |origin| %>
<%= origin.inputs :name => "Origin Address" do %>
<%= origin.input :line1 %>
....
<% end %>
<% end %>
<%= f.buttons do %>
<%= f.commit_button %>
<% end %>
<% end %>
I think you must define #lead before your form.

Resources