9

我有一个问题得到Devise工作的方式,我想单表继承。Rails:使用设计单表继承

我安排两个不同类型的帐户如下:

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注册。所有用户使用单一表格登录/account/sign_inAccount是父类)。

但是,通过此表单登录时似乎只对Account作用域进行身份验证。随后对诸如/user/edit/company/edit等操作的请求将用户引导至相应作用域的登录屏幕。

我该如何设计识别帐户'类型'并验证它们的相关范围?

任何建议非常感谢。

回答

8

我刚碰到确切的场景(带类名如问题中概述的那样改变)。这里是我的解决方案(设计2.2.3,导轨3.2.13):

在配置

/routes.rb中:

devise_for :accounts, :controllers => { :sessions => 'sessions' }, :skip => :registrations 
devise_for :users, :companies, :skip => :sessions 
在app /控制器/ 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类仍然是:可注册的,视图/ devise/shared/_links.erb中的默认链接将尝试发出,但new_registration_path(Accounts)将不起作用(我们:在路径绘图中跳过它)一个错误。您必须生成设计视图并手动删除它。

帽尖到https://groups.google.com/forum/?fromgroups=#!topic/plataformatec-devise/s4Gg3BjhG0E指向我在正确的方向。

+0

我用这个,我得到了错误NoMethodError(未定义的方法'类型'...在行sign_in(resource.type ...我需要做什么来改变这个? – Kevin 2014-10-08 00:20:02

+0

我猜只是做一个字符串列在帐户名称类型?并将其设置为模型名称? – Kevin 2014-10-08 01:37:29

+0

这也是我的猜测。ActiveRecord STI期望。 – 2014-12-08 18:05:34

0

尝试改变,像这样的路线:
devise_for:帐户,:用户:公司
因为设计采用复数形式的名称为它的资源

请让我知道,如果它帮助你

+0

感谢您的建议。不幸的是,这并没有解决问题。通过'/ accounts/sign_in'登录仍然不允许我访问'/ users/edit'或'/ companies/edit'。 – gjb 2011-04-17 19:09:16

1

如果不覆盖会议管理员,我不认为这是可能的。每个sign_in页面都有一个特定的作用域,这个作用域将根据你的路由所定义的进行验证。

通过在路径文件中使用devise_scope函数,可以为多个用户范围使用相同的sign_in页面,以强制执行:用户和:公司在页面中使用相同的登录(可以找到一个方法here),但我相当肯定,你将不得不修改会话控制器来执行一些自定义逻辑以确定哪种类型的用户正在登录。

+0

@gjb你怎么能够处理这个?你有没有找到更好的解决方案? – 2011-08-01 06:35:20

15

有一种简单的方法来处理路线中的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文件中指定的认证方法的方块:

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

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

+0

不应该:用户是:在这行代码中的公司?''#只有公司的路线 认证:用户,lambda {| u | u.type ==“公司”}做 结束''' – MDekker 2016-02-12 18:01:36