通过 ActiveAdmin 在 CanCan 中使用会话变量
using session variables in CanCan with ActiveAdmin
使用 Rails 4.2.1、ActiveAdmin 1.0.0pre2、CanCanCan 1.13.1
我需要使用会话变量作为我的 CanCan 授权的一部分。我想要这个(而不是将变量存储在数据库中)的原因是让管理员能够在多个同时会话中拥有不同的角色。
根据 this post 的说法,单独使用 CanCan 是可行的。但是,CanCan 本身无法访问会话变量,因此在初始化 Ability 时应将它们作为附加参数传入。
我到了可以成功修改 CanCan 适配器以将附加参数传递给 Ability.new 方法的地方,但是我在 ruby/rails 方面太没有受过教育,无法创建正确的上下文来访问会话变量.
这是我尝试过的:
config/initializers/active_admin.rb
#the usual
config.authorization_adapter = ActiveAdmin::CanCanAdapter
:
:
#at end of file, modify the standard CanCanAdapter class:
module ActiveAdmin
class CanCanAdapter < ActiveAdmin::AuthorizationAdapter
def initialize_cancan_ability
klass = resource.namespace.cancan_ability_class
klass = klass.constantize if klass.is_a? String
klass.new user, session
end
end
end
关键修改(相对于原来的CanCanAdapter Module)是"klass.new user, session[:admin_role]"行,我在其中添加了第二个参数session[:admin_role]。
app/models/ability.rb
class Ability
include CanCan::Ability
def initialize(user, session)
user ||= User.new # guest user (not logged in)
if user.is_admin? && session[:admin_role]==User.ROLE_ADMINISTERING
can :manage, :all
end
:
#other types of authorizations
:
end
end
虽然原则上该方法成功将第二个变量传递给 Ability 初始化,但它会抛出异常,因为 CanCanAdapter 无法访问 session 对象 class.
(即用例如文字常量替换行 klass.new user, session[:admin_role],我可以验证该常量是否已传递给 Ability 方法)。
那么,问题就变成了如何访问 CanCan 适配器中的会话?
根据 this post,使用 ActionDispatch::Request.new(ENV) 是可能的,但我无法充分理解讨论以完成这项工作。
也有帖子修改ActionController的方法如下:
def current_ability
@current_ability ||= Ability.new(current_user, session) #added session parameter
end
但我找不到放置这段代码的地方。
任何对我的方法的帮助,或对完成同样事情的另一种方法的建议,将不胜感激。
我不知道这是否是 "proper" 的方法,但它对我有用:
首先,我从 https://github.com/steveklabnik/request_store
添加了 request_store gem
gem 'request_store'
其次,我将此添加到我的 application_controller.rb 以保存会话数据。
before_filter :store_session_data
def store_session_data
RequestStore.store[:session] = session
end
第三,我修改了你修改后的适配器:
module ActiveAdmin
class CanCanAdapter < ActiveAdmin::AuthorizationAdapter
def initialize_cancan_ability
klass = resource.namespace.cancan_ability_class
klass = klass.constantize if klass.is_a? String
klass.new user, RequestStore.store[:session]
end
end
end
希望这对您有所帮助。
使用 Rails 4.2.1、ActiveAdmin 1.0.0pre2、CanCanCan 1.13.1
我需要使用会话变量作为我的 CanCan 授权的一部分。我想要这个(而不是将变量存储在数据库中)的原因是让管理员能够在多个同时会话中拥有不同的角色。
根据 this post 的说法,单独使用 CanCan 是可行的。但是,CanCan 本身无法访问会话变量,因此在初始化 Ability 时应将它们作为附加参数传入。
我到了可以成功修改 CanCan 适配器以将附加参数传递给 Ability.new 方法的地方,但是我在 ruby/rails 方面太没有受过教育,无法创建正确的上下文来访问会话变量.
这是我尝试过的:
config/initializers/active_admin.rb
#the usual
config.authorization_adapter = ActiveAdmin::CanCanAdapter
:
:
#at end of file, modify the standard CanCanAdapter class:
module ActiveAdmin
class CanCanAdapter < ActiveAdmin::AuthorizationAdapter
def initialize_cancan_ability
klass = resource.namespace.cancan_ability_class
klass = klass.constantize if klass.is_a? String
klass.new user, session
end
end
end
关键修改(相对于原来的CanCanAdapter Module)是"klass.new user, session[:admin_role]"行,我在其中添加了第二个参数session[:admin_role]。
app/models/ability.rb
class Ability
include CanCan::Ability
def initialize(user, session)
user ||= User.new # guest user (not logged in)
if user.is_admin? && session[:admin_role]==User.ROLE_ADMINISTERING
can :manage, :all
end
:
#other types of authorizations
:
end
end
虽然原则上该方法成功将第二个变量传递给 Ability 初始化,但它会抛出异常,因为 CanCanAdapter 无法访问 session 对象 class.
(即用例如文字常量替换行 klass.new user, session[:admin_role],我可以验证该常量是否已传递给 Ability 方法)。
那么,问题就变成了如何访问 CanCan 适配器中的会话? 根据 this post,使用 ActionDispatch::Request.new(ENV) 是可能的,但我无法充分理解讨论以完成这项工作。
也有帖子修改ActionController的方法如下:
def current_ability
@current_ability ||= Ability.new(current_user, session) #added session parameter
end
但我找不到放置这段代码的地方。
任何对我的方法的帮助,或对完成同样事情的另一种方法的建议,将不胜感激。
我不知道这是否是 "proper" 的方法,但它对我有用:
首先,我从 https://github.com/steveklabnik/request_store
添加了 request_store gemgem 'request_store'
其次,我将此添加到我的 application_controller.rb 以保存会话数据。
before_filter :store_session_data
def store_session_data
RequestStore.store[:session] = session
end
第三,我修改了你修改后的适配器:
module ActiveAdmin
class CanCanAdapter < ActiveAdmin::AuthorizationAdapter
def initialize_cancan_ability
klass = resource.namespace.cancan_ability_class
klass = klass.constantize if klass.is_a? String
klass.new user, RequestStore.store[:session]
end
end
end
希望这对您有所帮助。