gjb*_*gjb 11 ruby-on-rails single-table-inheritance devise ruby-on-rails-3
我遇到了一个问题,就是让Devise按照单表继承的方式工作.
我有两种不同类型的帐户,如下所示:
class Account < ActiveRecord::Base
devise :database_authenticatable, :registerable
end
class User < Account
end
class Company < Account
end
Run Code Online (Sandbox Code Playgroud)
我有以下路线:
devise_for :account, :user, :company
Run Code Online (Sandbox Code Playgroud)
用户注册/user/sign_up和公司注册/company/sign_up.所有用户都使用单个表单登录/account/sign_in(Account是父类).
但是,通过此表单登录似乎只是为Account范围验证它们.后续请求执行诸如/user/edit或/company/edit将用户指向相应范围的登录屏幕.
如何让Devise识别帐户"类型"并对相关范围进行身份验证?
任何建议非常感谢.
use*_*763 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
Run Code Online (Sandbox Code Playgroud)
一个经常被忽视的方法是您可以在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
Run Code Online (Sandbox Code Playgroud)
获取各种辅助方法,如"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
Run Code Online (Sandbox Code Playgroud)
这就是我解决了rails设计STI问题的方法.
小智 10
我刚刚遇到了问题中概述的确切场景(类名已更改).这是我的解决方案(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
Run Code Online (Sandbox Code Playgroud)
在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
Run Code Online (Sandbox Code Playgroud)
注意:由于您的Accounts类仍然是:可注册的,因此将尝试发出views/devise/shared/_links.erb中的默认链接,但new_registration_path(Accounts)将不起作用(我们:在路由图中跳过它)导致错误.您必须生成设计视图并手动删除它.
帽尖到https://groups.google.com/forum/?fromgroups=#!topic/plataformatec-devise/s4Gg3BjhG0E指着我在正确的方向.