thedanotto
thedanotto

Reputation: 7307

Rails Devise error on building one to one relationship upon registration

I want to create a one to one relationship, User -> Account upon Devise registration. I thought I had it figured out with the following code.

# account.rb
class Account < ActiveRecord::Base
  belongs_to :user
end

# user.rb
class User < ActiveRecord::Base
  has_one :account
end

# registrations_controller.rb
def create
  super
  current_user.build_account(account_params).save
end

And this code works about 80% of the time so far. But every once and a while, I get the following error.

undefined method 'build_account' for nil:NilClass app/controllers/users/registrations_controller.rb:13:in 'create'

Clearly, the error is telling me, you cannot build_account when current_user is nil. That makes sense to me, but

  1. Why does that happen only some of the time?
  2. What is a more consistent way to build this one to one relationship upon Devise user registration?

Upvotes: 0

Views: 168

Answers (1)

MZaragoza
MZaragoza

Reputation: 10111

When I do this I like to use nested forms.

# user.rb
class User < ActiveRecord::Base
  belongs_to :account
  accepts_nested_attributes_for :account
end

# account.rb
class Account < ActiveRecord::Base
  belongs_to :user
end

#views registrations/new.html.haml
  = simple_form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f|
  %ul
    - resource.errors.full_messages.each do |e|
      %li=e
        = f.simple_fields_for :account do |account_form|
          ...
        ...


#Controller
class Users::RegistrationsController < Devise::RegistrationsController
  def new
    resource = build_resource({})
    resource.build_account
    respond_with resource
  end

  def create
    build_resource(sign_up_params)
    if resource.save
      ...
    else
      ...
     end
   end

   private
   def sign_up_params
     allow = [:first_name, :last_name, :phone, :email, :password, :password_confirmation, :agree_newsleter, account_attributes: [:name, :phone, :website]]
     params.require(resource_name).permit(allow)
   end

end

Upvotes: 3

Related Questions