Question

Each user in the application has a profile that has to be filled out by the user when registering. The user and profile classes are as follows:

user.rb:

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable, :rememberable, :trackable, :validatable
  has_one :profile
end

profile.rb:

class Profile < ActiveRecord::Base
  belongs_to :user
end

the view form:

= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|
  = f.input :email, required: true, autofocus: true
  = f.simple_fields_for :profile do |pf|
    = pf.input :name
    = pf.input :bio
  = f.input :password, required: true
  = f.input :password_confirmation, required: true
  = f.button :submit

The problem is that the profile object needs to be initialized before the form is rendered. I decided to override the new method of the Devise::RegistrationsController:

class Users::RegistrationsController < Devise::RegistrationsController
  before_filter :configure_permitted_parameters
  def new
      build_resource({})     # copied from super
      resource.build_profile # my custom initialization code
      respond_with self.resource # copied from super
  end

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:sign_up) << { profile_attributes: [:name, :bio] } 
  end
end

This doesn't seem to be very DRY since I am duplicating the code in the super new method. I might also break things if the super controller method new changes when the gem is upgraded. Any better way to override the resource (user) creation without duplicating code?

Was it helpful?

Solution

You can try to only change the User model:

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable, :rememberable, :trackable, :validatable
  has_one :profile
  accepts_nested_attributes_for :profile

  def profile
    super || build_profile
  end
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top