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?

Était-ce utile?

La 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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top