3

我的系統中有不同種類的用戶。一種是設計師:如何在Rails的註冊表單中創建Devise User時創建另一個對象?

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

這是在用戶註冊時立即創建的。因此,當用戶填寫sign_up表單時,會創建一個Devise User以及此Designer對象,並將其user_id設置爲創建的新User。如果我有權訪問控制器的代碼,這很容易。但是對於Devise,我無法訪問此註冊控制器。

註冊時創建UserDesigner的正確方法是什麼?

回答

8

在最近的一個項目中,我用form object pattern一步創建了Devise用戶和公司。這涉及繞過Devise的RegistrationsController並創建您自己的SignupsController。

# 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 

引用的註冊模型被定義爲表單對象。

# 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 

對錶單對象(和我的工作來源)的優秀閱讀是this CodeClimate blog post on Refactoring

總而言之,我更喜歡這種方法,而非使用accepts_nested_attributes_for,儘管可能有更大的方法。讓我知道如果你找到一個!

===

編輯:增加了引用模型及其關聯更好地理解。

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 

這種結構在模型建模旁邊saucy,寶石由thoughtbot。來源不在Github AFAIK上,但可以從寶石中提取。我通過改造來學習很多東西。

+0

我們如何堅持這一到數據庫假設我們有一個賬號,用戶和會員的ActiveRecord模型。您是否介意發佈該窗體本身的外觀以及該控制器的主動記錄模型。謝謝。 – brg 2013-04-23 14:58:34

+0

添加了模型結構。持久化由控制器中調用的@ signup.save處理,它創建所有對象及其關聯。 – 2013-04-23 18:28:26

+0

你是一位紳士學者,謝謝。 – brg 2013-04-23 18:59:40

2

如果您不想變更登記控制器,一個方法是使用ActiveRecord的回調

class User < ActiveRecord::Base 
    after_create :create_designer 

    private 

    def create_designer 
     Designer.create(user_id: self.id) 
    end 
end 
+0

回調不起作用,因爲我無法訪問參數散列 – 2013-03-26 05:01:20

+0

這正是我所需要的!謝謝 – 2016-09-28 06:44:36

相關問題