Rails:使用具有单表inheritance的Devise

我遇到了一个问题,就是让Devise按照我对单表inheritance的方式工作。

我有两种不同类型的帐户,如下所示:

class Account < ActiveRecord::Base devise :database_authenticatable, :registerable end class User < Account end class Company < Account end 

我有以下路线:

 devise_for :account, :user, :company 

用户在/user/sign_up注册, /company/sign_up/company/sign_up注册。 所有用户使用/account/sign_in的单个表单/account/sign_inAccount是父类)。

但是,通过此表单登录似乎只是为Account范围validation它们。 对/user/edit/company/edit等操作的后续请求将用户指向相应范围的登录屏幕。

如何让Devise识别帐户“类型”并对相关范围进行身份validation?

任何建议非常感谢。

我刚刚遇到了问题中概述的确切场景(类名已更改)。 这是我的解决方案(Devise 2.2.3,Rails 3.2.13):

在config / routes.rb中:

 devise_for :accounts, :controllers => { :sessions => 'sessions' }, :skip => :registrations devise_for :users, :companies, :skip => :sessions 

在app / controllers / sessions_controller.rb中:

 class SessionsController < Devise::SessionsController def create rtn = super sign_in(resource.type.underscore, resource.type.constantize.send(:find, resource.id)) unless resource.type.nil? rtn end end 

注意:由于您的Accounts类仍然是:可注册的,因此将尝试发出views / devise / shared / _links.erb中的默认链接,但new_registration_path(Accounts)将不起作用(我们:在路由图中跳过它)导致错误。 您必须生成设计视图并手动删除它。

提示https://groups.google.com/forum/?fromgroups=#!topic/plataformatec-devise/s4Gg3BjhG0E,以便为我指明正确的方向。

有一种简单的方法来处理路线中的STI。

假设您有以下STI型号:

 def Account < ActiveRecord::Base # put the devise stuff here devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable end def User < Account end def Company < Account 

一个经常被忽视的方法是您可以在routes.rb文件中的authenticated方法中指定一个块:

 ## config/routes.rb devise_for :accounts, :skip => :registrations devise_for :users, :companies, :skip => :sessions # routes for all users authenticated :account do end # routes only for users authenticated :user, lambda {|u| u.type == "User"} do end # routes only for companies authenticated :user, lambda {|u| u.type == "Company"} do end 

获取各种辅助方法,如“current_user”和“authenticate_user!” (“current_account”和“authenticate_account!”已定义),无需为每个方法定义单独的方法(随着添加更多用户类型而迅速变得不可维护),您可以在ApplicationController中定义动态帮助器方法:

 ## controllers/application_controller.rb def ApplicationController < ActionController::Base %w(User Company).each do |k| define_method "current_#{k.underscore}" do current_account if current_account.is_a?(k.constantize) end define_method "authenticate_#{k.underscore}!" do |opts={}| send("current_#{k.underscore}") || not_authorized end end end 

这就是我解决rails设计STI问题的方法。

如果不覆盖会话控制器,我认为这是不可能的。 每个sign_in页面都有一个特定的范围,设计将根据您的路由进行身份validation。

通过在路径文件中使用devise_scope函数可以对同一个sign_in页面使用相同的sign_in页面来强制:users和:公司使用相同的登录页面(可以在这里找到方法),但是我非常肯定你必须修改会话控制器来做一些自定义逻辑,以确定登录的用户类型。

尝试改变这样的路线:
devise_for:accounts,:users,:companies
因为Devise为它的资源使用复数名称

如果有帮助,请告诉我