Ruby-on-rails 设计和多个“用户”模型
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9472852/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
devise and multiple "user" models
提问by ddidier
I'm using rails 3.2 and devise 2.0 and I'm quite new to Rails.
我正在使用 rails 3.2 并设计 2.0 并且我对 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
- 有 2 个或更多“用户”模型,例如。会员、客户、管理员
- 所有模型共享一些必填字段(例如电子邮件和密码)
- 每个模型可能有一些独特的字段(例如,仅限客户的公司)
- 某些字段可能是共享的,但没有相同的验证(例如,客户需要姓名,但会员可选)
- 所有字段都必须在注册过程中填写,所以表格是不同的
- 登录表单应该是唯一的
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:
我用谷歌搜索并搜索了 StackOverflow 很长一段时间,但对我来说似乎没有什么是正确的(我是 Java 人,抱歉 :) 现在我很困惑。出现了两种解决方案:
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?
这解决了自定义注册过程,对我来说似乎是正确的,但唯一的登录表单是一个阻止程序。我在 SO ( Devise - login from two model)上找到了一个答案,它建议覆盖 Devise::Models::Authenticatable.find_for_authentication(conditions)。这看起来很复杂(?),因为我是 Rails 的新手,我想知道这是否可行?
Thanks for your advice!
谢谢你的建议!
采纳答案by ddidier
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:
模型/用户.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-formsand http://pastie.org/1084054to have two registration paths with an overridden controller:
然后我调整了http://railscasts.com/episodes/217-multistep-forms和http://pastie.org/1084054以具有两个带有覆盖控制器的注册路径:
config/routes.rb:
配置/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:
控制器/用户/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.rbnew_client.rbincluding a partial according to the wizard step:_new_client_1.rb_new_client_2.rb
new_member.rbincluding a partial according to the wizard step:_new_member_1.rb_new_member_2.rb
new.rbnew_client.rb包括根据向导步骤的部分内容:_new_client_1.rb_new_client_2.rb
new_member.rb包括根据向导步骤的部分内容:_new_member_1.rb_new_member_2.rb
回答by mohamagdy
Welcome aboard Java guy =), I hope you'll enjoy the Rails world. Simply, to solve your issue you have 2 solutions:
欢迎使用 Java 家伙 =),我希望您会喜欢 Rails 世界。简单地说,要解决您的问题,您有两种解决方案:
- For each user create a table in the database and corresponding model.
- Create a single table in the database and for each user type create a model. This is called single table inheritance (STI).
- 为每个用户在数据库中创建一个表和相应的模型。
- 在数据库中创建一个表,并为每个用户类型创建一个模型。这称为单表继承 (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.
选择哪一个?这取决于角色的共同属性。如果它们几乎很常见(例如都有姓名、电子邮件、手机等)并且一些属性不同,我强烈推荐 STI 解决方案。
How to do the STI?
1. Simply create the the devise user model and table using the command rails generate devise User2. Add a column named typewith 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
性病怎么办?1. 使用命令简单地创建设计用户模型和表rails generate devise User2.type使用迁移将一个以字符串数据类型命名的列添加到数据库中的用户表中。3. 为每个用户类型创建一个模型(例如rails g model admin) 4. 使 Admin 类继承自用户模型
class Admin < User
end
That's it you are done =) ... Yupeee
就是这样你完成了 =) ... Yupeee
To create an admin run the command Admin.create(...)where the dots is the admin attributes for example the email, name, ...
要创建管理员,请运行命令Admin.create(...),其中点是管理员属性,例如电子邮件、姓名、...
I think this questioncould help you too
我认为这个问题也可以帮助你
回答by tw airball
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.
我和你的情况类似,在尝试了各种方法后,我使用了一个属于多态角色的 User 模型。这似乎是实现单点登录的最简单方法。
The User model would contain the information specific to log-in only.
User 模型将仅包含特定于登录的信息。
The Role model would store fields specific to each role, as well as other associations specific to the role.
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
控制器——你必须为嵌套属性 build_user
#controllers/members_controller.rb
def new
@member = Member.new
@member.build_user
end
def create
#... standard controller stuff
end
views/members/new.html.erb
意见/成员/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.
我想指出,没有必要接触nested_form gem;因为要求是用户只能属于一种类型的角色。
回答by Hauleth
So what's wrong? Just run rails g devise:views [model_name], customize each registration forms and in config/initializer/devise.rbjust put config.scoped_views = true.
那么怎么了?只需运行rails g devise:views [model_name],自定义每个注册表单,然后config/initializer/devise.rb就可以了config.scoped_views = true。

