11

I have the same issue as Creating an additional related model with Devise (which has no answer).

I have overridden the devise view for creating a new user and added a company name, I have changed the model to use accepts_nested_attributes_for

There are no errors, but it is not adding the nested record and I don't have a controller where I can modify the request.

I have the following (shortened to make it readable):

routes.rb

map.devise_for :users
map.resources :users, :has_many => :companies

user.rb

has_many :companies
accepts_nested_attributes_for :companies
devise :registerable ... etc

company.rb

belongs_to :user

new.html.erb

...
<% form_for resource_name, resource, :url => registration_path(resource_name) do |f| %>
...
  <% f.fields_for :company do |company_form| %>
    <p><%= company_form.label :name %></p>
    <p><%= company_form.text_field :name %></p>
  <% end %>
...

UPDATE: I didn't add :company to the attr_accessible list in the User model.

Community
  • 1
  • 1
Craig McGuff
  • 3,968
  • 6
  • 30
  • 35

3 Answers3

16

You can add the following method to the User model:

user.rb

def with_company
  self.companies.build
  self
end

And modify the view:

new.html.erb

...
<% form_for [resource_name, resource.with_company], :url => registration_path(resource_name) do |f| %>
...
  <% f.fields_for :company do |company_form| %>
  ...
  <% end %>

This way, you'll have the nested form to add one company to the user. To dynamically add multiple companies to the user, check the Railcast #197 by Ryan Bates. Make sure you are passing the pair of resources as an array, otherwide you will get an error like this: "wrong number of arguments (3 for 2)".

Ivan Prasol
  • 303
  • 1
  • 7
  • I don't know how good this solution fits in the MVC Modell but it works. – ThreeFingerMark Dec 23 '10 at 22:27
  • 2
    You should only build it once, or it gets built each time you submit the form `self.companies.build if self.companies.empty?` – meleyal Feb 25 '11 at 17:12
  • 3
    why pass in resource_name, shouldn't below works too? <% form_for resource.with_company, ... – GeorgeW Mar 07 '12 at 16:05
  • 2
    For anyone using this solution, both @meleyal and @GeorgeW are correct. However, watch out for ActiveRecord lazy loading, use `self.companies.build if self.companies(true).empty?`, otherwise `empty?` might return true even though it shouldn't. – JeanMertz Apr 11 '12 at 09:33
2

You may be trying to mass assign some protected variable, OR you might not be saving a valid record. Check to make sure that the record is actually saving to the db.

Preston Marshall
  • 1,185
  • 1
  • 8
  • 15
  • Yep - it was a mass-assign, I was not defining :company in the attr_accessible in user.rb new problem now - purely a devise issue – Craig McGuff Aug 23 '10 at 09:17
0

I realised this is a very old thread, but since I found a better solution, hence the reply.

Just change the new.html.erb as follows,

<% form_for(resource, :as => resource_name,:url => registration_path(resource_name) do |f| %>
    ...
    <% prefix = "user[company_attributes]"%>
    <% fields_for prefix, @user.company do |company_form| %>
    ...
    <% end %>
<% end %>

This way when @user.save gets invoked, it would run company.save too with all the validations you may have in company model.

I don't have whole lot of RoR experience, but I think this is a better solution. What do you think?

John Conde
  • 217,595
  • 99
  • 455
  • 496
Atarang
  • 422
  • 1
  • 6
  • 22
  • Actually, this is exactly what `fields_for :company do |company_form|` does. So this is not a better solution. – nathanvda Dec 10 '11 at 09:35