devise and multiple “user” models

前端 未结 4 1633
[愿得一人]
[愿得一人] 2020-11-27 09:21

I\'m using rails 3.2 and devise 2.0 and I\'m quite new to Rails.

Requirements

I\'d like to achieve the following:

  • have 2 or more \"user\" mod
相关标签:
4条回答
  • 2020-11-27 09:37

    Welcome aboard Java guy =), I hope you'll enjoy the Rails world. Simply, to solve your issue you have 2 solutions:

    1. For each user create a table in the database and corresponding model.
    2. Create a single table in the database and for each user type create a model. This is called single table inheritance (STI).

    Which one to choose? It depends on the common attributes of the roles. If they are almost common (for example all have a name, email, mobile, ...) and a few attributes are different, I highly recommend the STI solution.

    How to do the STI? 1. Simply create the the devise user model and table using the command rails generate devise User 2. Add a column named type with string datatype to the user table in the database using a migration. 3. For each user type create a model (for example rails g model admin) 4. Make the Admin class inherits from user model

    class Admin < User
    end
    

    That's it you are done =) ... Yupeee

    To create an admin run the command Admin.create(...) where the dots is the admin attributes for example the email, name, ...

    I think this question could help you too

    0 讨论(0)
  • 2020-11-27 09:40

    I found a way to go and I'm quite happy with it so far. I'll describe it here for others.

    I went with the single "user" class. My problem was to achieve a customized registration process for each pseudo model.

    model/user.rb:

    class User < ActiveRecord::Base
      devise :confirmable,
           :database_authenticatable,
           :lockable,
           :recoverable,
           :registerable,
           :rememberable,
           :timeoutable,
           :trackable,
           :validatable
    
      # Setup accessible (or protected) attributes for your model
      attr_accessible :email, :password, :password_confirmation, :remember_me, :role
    
      as_enum :role, [:administrator, :client, :member]
      validates_as_enum :role
      ## Rails 4+ for the above two lines
      # enum role: [:administrator, :client, :member]
    
    end
    

    Then I adapted http://railscasts.com/episodes/217-multistep-forms and http://pastie.org/1084054 to have two registration paths with an overridden controller:

    config/routes.rb:

    get  'users/sign_up'   => 'users/registrations#new',        :as => 'new_user_registration'
    
    get  'clients/sign_up' => 'users/registrations#new_client', :as => 'new_client_registration'
    post 'clients/sign_up' => 'users/registrations#create',     :as => 'client_registration'
    
    get  'members/sign_up' => 'users/registrations#new_member', :as => 'new_member_registration'
    post 'members/sign_up' => 'users/registrations#create',     :as => 'member_registration'
    

    controllers/users/registrations_controller.rb:

    I created a wizard class which knows the fields to validate at each step

    class Users::RegistrationsController < Devise::RegistrationsController
    
        # GET /resource/sign_up
        def new
            session[:user] ||= { }
            @user = build_resource(session[:user])
            @wizard = ClientRegistrationWizard.new(current_step)
    
            respond_with @user
        end
    
        # GET /clients/sign_up
        def new_client
            session[:user] ||= { }
            session[:user]['role'] = :client
            @user = build_resource(session[:user])
            @wizard = ClientRegistrationWizard.new(current_step)
    
            render 'new_client'
        end
    
        # GET /members/sign_up
        def new_member
          # same
        end
    
        # POST /clients/sign_up
        # POST /members/sign_up
        def create
            session[:user].deep_merge!(params[:user]) if params[:user]
            @user = build_resource(session[:user])
            @wizard = ClientRegistrationWizard.new(current_step)
    
            if params[:previous_button]
                @wizard.previous
            elsif @user.valid?(@wizard)
                if @wizard.last_step?
                    @user.save if @user.valid?
                else
                    @wizard.next
                end
            end
    
            session[:registration_current_step] = @wizard.current_step
    
            if @user.new_record?
                clean_up_passwords @user
                render 'new_client'
            else
                #session[:registration_current_step] = nil
                session[:user_params] = nil
    
                if @user.active_for_authentication?
                    set_flash_message :notice, :signed_up if is_navigational_format?
                    sign_in(:user, @user)
                    respond_with @user, :location => after_sign_up_path_for(@user)
                else
                    set_flash_message :notice, :"signed_up_but_#{@user.inactive_message}" if is_navigational_format?
                    expire_session_data_after_sign_in!
                    respond_with @user, :location => after_inactive_sign_up_path_for(@user)
                end
            end
    
        end
    
        private
    
        def current_step
            if params[:wizard] && params[:wizard][:current_step]
                return params[:wizard][:current_step]
            end
            return session[:registration_current_step]
        end
    
    end
    

    and my views are:

    • new.rb
    • new_client.rb including a partial according to the wizard step:
      • _new_client_1.rb
      • _new_client_2.rb
    • new_member.rb including a partial according to the wizard step:
      • _new_member_1.rb
      • _new_member_2.rb
    0 讨论(0)
  • 2020-11-27 10:00

    I'm in similar shoes as you, after trying all sorts of approaches I went with a single User model, which would belong to polymorphic roles. This seems like the simplest way to achieve single-login.

    The User model would contain the information specific to log-in only.

    The Role model would store fields specific to each role, as well as other associations specific to the role.

    New registrations would be customized for each user type (roles) via individual controllers, and then building nested attributes for the User.

    class User < ActiveRecord::Base
        #... devise code ...
        belongs_to :role, :polymorphic => true
    end
    
    class Member < ActiveRecord::Base
        attr_accessible :name, :tel, :city  #etc etc....
        attr_accessible :user_attributes #this is needed for nested attributes assignment
    
        #model specific associations like  
        has_many :resumes
    
        has_one :user, :as => :role, dependent: :destroy
        accepts_nested_attributes_for :user
    end 
    

    Routes -- just regular stuff for the Member model.

    resources :members
    #maybe make a new path for New signups, but for now its new_member_path
    

    Controller -- you have to build_user for nested attributes

    #controllers/members_controller.rb
    def new
        @member = Member.new
        @member.build_user
    end
    
    def create
        #... standard controller stuff
    end
    

    views/members/new.html.erb

    <h2>Sign up for new members!</h2>
    <%= simple_form_for @member do |f| %>
    
        # user fields
        <%= f.fields_for :user do |u| %>
          <%= u.input :email, :required => true, :autofocus => true %>
          <%= u.input :password, :required => true %>
          <%= u.input :password_confirmation, :required => true %>
        <% end %>
    
        # member fields
        <%= f.input :name %>
        <%= f.input :tel %>
        <%= f.input :city %>
    
        <%= f.button :submit, "Sign up" %>
    <% end %>
    

    I would like to point out that there is NO NEED to reach for nested_form gem; since the requirement is that User can only belong_to one type of Role.

    0 讨论(0)
  • So what's wrong? Just run rails g devise:views [model_name], customize each registration forms and in config/initializer/devise.rb just put config.scoped_views = true.

    0 讨论(0)
提交回复
热议问题