devise and multiple “user” models

匿名 (未验证) 提交于 2019-12-03 02:12:02

问题:

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" models, eg. Member, Customer, Admin
  • all models share some required fields (eg. email and password)
  • each model may have some unique fields (eg. company for Customer only)
  • some fields may be shared but not have the same validation (eg. name is required for Customer but optional for Member)
  • all fields must be filled during the registration process, so the forms are different
  • the login form should be unique

Possible solutions

I googled and searched StackOverflow for quite a long time, but nothing seems right to me (I'm a Java guy, sorry :) and now I'm quite confused. Two solutions came up:

Single devise user

That's the most frequent answer. Just create the default devise User and create relations between Member-->User and Customer-->User. My concern here is how can I achieve a customized registration process for each model? I tried different things but all ended as a mess!

Multiple devise users

This solves the custom registration process, and seems right to me, but the unique login form is a blocker. I found an answer on SO (Devise - login from two model) which suggests to override Devise::Models::Authenticatable.find_for_authentication(conditions). That seems complicated (?) and since I'm new to rails, I'd like to know if that could work?

Thanks for your advice!

回答1:

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 

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



回答2:

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  true end  class Member  :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

Sign up for new members!

# user fields true, :autofocus => true %> true %> true %> # member fields

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.



回答3:

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 

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  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


回答4:

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.



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!