3

Using Rails 4.2.1, ActiveAdmin 1.0.0pre2, CanCanCan 1.13.1

I need to use session variables as part of my CanCan authorization. The reason I want this (instead of storing the variable in the database) is to enable an admin to have different roles on multiple simultaneous sessions.

According to this post it is or was possible using CanCan alone. But, CanCan itself does not have access to the session variables and so they should be passed in as an additional parameter when initializing an Ability.

I got to where I can successfully modify the CanCan adapter to pass additional parameters to the Ability.new method, but I am too uneducated in ruby/rails to create the correct context to access the session variables.

Here's what I tried:

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

The key modification (relative to original CanCanAdapter Module) is the line "klass.new user, session[:admin_role]" in which I added the second parameter 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

Although this method was successful in principle to pass a second variable to the Ability initialization, it throws up an exception because the session object is not accessible to the CanCanAdapter class.

(i.e. replace the line klass.new user, session[:admin_role] with e.g. a literal constant, and I can verify that the constant is passed to the Ability method).

So, the question becomes how can I access the session in the CanCan Adapter? According to this post, it is possible using ActionDispatch::Request.new(ENV), but I was unable to understand the discussion enough to make this work.

There have also been posts related to modifying the ActionController method as follows:

def current_ability
  @current_ability ||= Ability.new(current_user, session) #added session parameter
end

but I was not able to find a place to put this code that made a difference.

Any help with my method, or suggestions for another method to accomplish the same thing, would be greatly appreciated.

Community
  • 1
  • 1
Eli R.
  • 188
  • 11

1 Answers1

1

I don't know if this is the "proper" way to do this, but it worked for me:

First, I added the request_store gem from https://github.com/steveklabnik/request_store

gem 'request_store'

Second, I added this to my application_controller.rb to save the session data.

  before_filter :store_session_data

  def store_session_data
    RequestStore.store[:session] = session
  end

Third, I modified your revised adapter as such:

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

Hope this helps.

kayatela
  • 394
  • 5
  • 21