How to create another object when creating a developer user from my registration form in Rails?

There are different users on my system. One type is, say, a designer:

class Designer < ActiveRecord::Base attr_accessible :user_id, :portfolio_id, :some_designer_specific_field belongs_to :user belongs_to :portfolio end 

This is created immediately when the user subscribes. Therefore, when a user fills out the sign_up form, a Devise User is created with this Designer object with its user_id set to the new User that was created. This is easy enough if I have access to the controller code. But with Devise, I don't have access to this registration controller.

What is the correct way to create User and Designer when registering?

+4
source share
2 answers

In a recent project, I used a form object template to create both a developer user and a company in one step. This includes going around the Devise RegistrationsController and creating your own RegistersController.

 # config/routes.rb # Signups get 'signup' => 'signups#new', as: :new_signup post 'signup' => 'signups#create', as: :signups # app/controllers/signups_controller.rb class SignupsController < ApplicationController def new @signup = Signup.new end def create @signup = Signup.new(params[:signup]) if @signup.save sign_in @signup.user redirect_to projects_path, notice: 'You signed up successfully.' else render action: :new end end end 

A related registration model is defined as a form object.

 # app/models/signup.rb # The signup class is a form object class that helps with # creating a user, account and project all in one step and form class Signup # Available in Rails 4 include ActiveModel::Model attr_reader :user attr_reader :account attr_reader :membership attr_accessor :name attr_accessor :company_name attr_accessor :email attr_accessor :password validates :name, :company_name, :email, :password, presence: true def save # Validate signup object return false unless valid? delegate_attributes_for_user delegate_attributes_for_account delegate_errors_for_user unless @user.valid? delegate_errors_for_account unless @account.valid? # Have any errors been added by validating user and account? if !errors.any? persist! true else false end end private def delegate_attributes_for_user @user = User.new do |user| user.name = name user.email = email user.password = password user.password_confirmation = password end end def delegate_attributes_for_account @account = Account.new do |account| account.name = company_name end end def delegate_errors_for_user errors.add(:name, @user.errors[:name].first) if @user.errors[:name].present? errors.add(:email, @user.errors[:email].first) if @user.errors[:email].present? errors.add(:password, @user.errors[:password].first) if @user.errors[:password].present? end def delegate_errors_for_account errors.add(:company_name, @account.errors[:name].first) if @account.errors[:name].present? end def persist! @user.save! @account.save! create_admin_membership end def create_admin_membership @membership = Membership.create! do |membership| membership.user = @user membership.account = @account membership.admin = true end end end 

A great read of form objects (and the source for my work) is a CodeClimate blog post by Refactoring .

In general, I strongly prefer this approach using accepts_nested_attributes_for , although there may be even more possibilities. Let me know if you find it!

===

Edit: Added reference models and their associations for better understanding.

 class User < ActiveRecord::Base # Memberships and accounts has_many :memberships has_many :accounts, through: :memberships end class Membership < ActiveRecord::Base belongs_to :user belongs_to :account end class Account < ActiveRecord::Base # Memberships and members has_many :memberships, dependent: :destroy has_many :users, through: :memberships has_many :admins, through: :memberships, source: :user, conditions: { 'memberships.admin' => true } has_many :non_admins, through: :memberships, source: :user, conditions: { 'memberships.admin' => false } end 

This structure in the model is modeled along with saucy , a gem from thoughtful. The source is not on Github AFAIK, but can extract it from a gem. I learned a lot by redoing it.

+9
source

If you do not want to change the registration controller, one way is to use ActiveRecord callbacks

 class User < ActiveRecord::Base after_create :create_designer private def create_designer Designer.create(user_id: self.id) end end 
+2
source

All Articles