You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails双用户角色注册:创建后分配角色的实现问询

Got it, let's walk through how to set this up properly—separate registration forms for clients and businesses with Devise, then assign roles after the user completes their profile, not during sign-up. I'll cover both the enum and rolify approaches since you're weighing both options.

1. First: Set Up Separate Devise Registration Forms

First, we need to split the registration flow for clients and businesses so each has their own form, but we'll avoid assigning roles during the initial user creation.

Step 1: Create Custom Registration Controllers

Make two controllers that inherit from Devise's base RegistrationsController—one for clients, one for businesses:

# app/controllers/client_registrations_controller.rb
class ClientRegistrationsController < Devise::RegistrationsController
  def new
    super
    # You can prepopulate any form data here if needed, but no role assignment yet
  end

  def create
    build_resource(sign_up_params)
    resource.save

    if resource.persisted?
      if resource.active_for_authentication?
        set_flash_message! :notice, :signed_up
        sign_up(resource_name, resource)
        # Redirect to the client profile creation page (we'll build this next)
        redirect_to new_client_profile_path, notice: "Account created! Please complete your client profile."
      else
        set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
        expire_data_after_sign_in!
        redirect_to after_inactive_sign_up_path_for(resource)
      end
    else
      clean_up_passwords resource
      set_minimum_password_length
      respond_with resource
    end
  end

  private

  def sign_up_params
    # Only collect core user fields—no role-related params here
    params.require(:user).permit(:email, :password, :password_confirmation)
  end
end

Repeat this for businesses, adjusting the redirect path to new_business_profile_path:

# app/controllers/business_registrations_controller.rb
class BusinessRegistrationsController < Devise::RegistrationsController
  def new
    super
  end

  def create
    build_resource(sign_up_params)
    resource.save

    if resource.persisted?
      if resource.active_for_authentication?
        set_flash_message! :notice, :signed_up
        sign_up(resource_name, resource)
        redirect_to new_business_profile_path, notice: "Account created! Please complete your business profile."
      else
        set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
        expire_data_after_sign_in!
        redirect_to after_inactive_sign_up_path_for(resource)
      end
    else
      clean_up_passwords resource
      set_minimum_password_length
      respond_with resource
    end
  end

  private

  def sign_up_params
    params.require(:user).permit(:email, :password, :password_confirmation)
  end
end

Step 2: Update Routes

Point Devise's registration routes to your new controllers in config/routes.rb:

devise_scope :user do
  # Client registration routes
  get "/clients/sign_up", to: "client_registrations#new"
  post "/clients/sign_up", to: "client_registrations#create"

  # Business registration routes
  get "/businesses/sign_up", to: "business_registrations#new"
  post "/businesses/sign_up", to: "business_registrations#create"

  # Keep default Devise routes for login, password reset, etc.
  devise_for :users, skip: [:registrations]
end
2. Option 1: Use Enum for Roles

This is a lightweight option if you only have two fixed roles (client and business).

Step 1: Add Role Column to Users

Generate a migration to add a role string column:

rails generate migration AddRoleToUsers role:string
rails db:migrate

Step 2: Configure Enum in User Model

Set up the enum with a default "unassigned" role (so users don't get a role until they complete their profile):

# app/models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  # Define enum roles
  enum role: [:unassigned, :client, :business]
  # Set default role to unassigned for new users
  after_initialize :set_default_role, if: :new_record?

  # Associations for profiles (you'll need these models too)
  has_one :client_profile, dependent: :destroy
  has_one :business_profile, dependent: :destroy

  private

  def set_default_role
    self.role ||= :unassigned
  end
end

Step 3: Assign Role When Profile is Created

When the user submits their client profile, assign the client role in the profile's create action:

# app/controllers/client_profiles_controller.rb
class ClientProfilesController < ApplicationController
  before_action :authenticate_user!

  def new
    @client_profile = current_user.build_client_profile
  end

  def create
    @client_profile = current_user.build_client_profile(client_profile_params)

    if @client_profile.save
      # Assign the client role here
      current_user.client!
      redirect_to client_dashboard_path, notice: "Profile completed! Your client role has been activated."
    else
      render :new
    end
  end

  private

  def client_profile_params
    # Add your client profile fields here
    params.require(:client_profile).permit(:full_name, :phone_number, :address)
  end
end

Do the same for businesses—use current_user.business! in the BusinessProfilesController#create action.

3. Option 2: Use Rolify for Roles

Rolify is better if you might add more roles later or need more flexible role management.

Step 1: Install Rolify

Add the gem to your Gemfile:

# Gemfile
gem 'rolify'

Install and run the generator:

bundle install
rails generate rolify Role User
rails db:migrate

Step 2: Configure User Model

Update your User model to include rolify (no default roles—users start with none):

# app/models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  rolify
  has_one :client_profile, dependent: :destroy
  has_one :business_profile, dependent: :destroy
end

Step 3: Assign Role When Profile is Created

In the profile controller's create action, add the role using Rolify's add_role method:

# app/controllers/client_profiles_controller.rb
class ClientProfilesController < ApplicationController
  before_action :authenticate_user!

  def new
    @client_profile = current_user.build_client_profile
  end

  def create
    @client_profile = current_user.build_client_profile(client_profile_params)

    if @client_profile.save
      # Assign client role via Rolify
      current_user.add_role :client
      redirect_to client_dashboard_path, notice: "Profile completed! Your client role has been activated."
    else
      render :new
    end
  end

  private

  def client_profile_params
    params.require(:client_profile).permit(:full_name, :phone_number, :address)
  end
end

For businesses, use current_user.add_role :business in their profile controller.

4. Bonus: Add Permission Checks

To make sure users can only create the profile matching their intended role (or no role yet), use a gem like Pundit or CanCanCan. For example, with Pundit:

Create a UserPolicy:

# app/policies/user_policy.rb
class UserPolicy < ApplicationPolicy
  def create_client_profile?
    # Allow unassigned users or existing clients to edit their profile
    user.roles.empty? || user.has_role?(:client)
  end

  def create_business_profile?
    user.roles.empty? || user.has_role?(:business)
  end
end

Then authorize in your profile controllers:

# In client_profiles_controller.rb
def new
  authorize current_user, :create_client_profile?
  @client_profile = current_user.build_client_profile
end

That's it! This setup keeps role assignment separate from registration, letting users complete their profile first before gaining role-specific permissions.

内容的提问来源于stack exchange,提问作者Mohamed Ahmed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:06:32