1

So I have the following setup:

class User < AR
  has_many :memberships
  has_many :user_groups, through: :memberships
  has_many :organizations, through: :memberships
end

class Membership < AR
  belongs_to :user
  belongs_to :user_group
  belongs_to :organization
end

class UserGroup < AR
  has_many :memberships
  has_many :users, through: :memberships
  has_many user_groups, through: :memberships
end

So one user can be e member of several user groups throughout different organizations, i.e. he/she can be a product manager in organization A and an article manager and a comment manager in organization B.

So in order to be able to ask can? :manage, an_article_instance I somehow need to have abilities set like so:

class Ability
  if user.is_content_manager_for(currently_selected_organization)
    can :manage, Article

  elsif user.is_admin_for(currently_selected_organization)
    can :manage, User, memberships: { organization_id: currently_selected_organization }
  end
end

The web interface of the backend is supposed to have a select menu where the user can select on which organization he/she wants to work on. So I was thinking of maybe storing the currently selected organization in the session, since it is persistent data throughout a whole work session.

But to access a helper method like currently_selected_organization (or the session directly) in the Ability (or any other) model would actually violate the MVC pattern. I've read in several locations that this is not good, etc, etc.

So I'm wondering if there's a better/cleaner way of doing this?

Vapire
  • 4,568
  • 3
  • 24
  • 41

1 Answers1

4

Ok, so I figured it out with a different approach. CanCan adds a current_ability method to ActionController::Base which instantiates a new Ability object and passes the current_user object to it. One can simply overwrite the current_ability method in an own controller, so I ended up doing this:

class ApplicationController < ActionController::Base
  def current_ability
    @current_ability ||= Ability.new(current_user, Organization.find_by(id: cookies[:current_organization])
  end
end

class Ability
  include CanCan::Ability

  def initialize(user, currently_selected_organization)
    if user.is_admin_for(currently_selected_organization
      # ...
    end
  end
end

This way it doesn't break the MVC pattern and I didn't end up including helper modules or hack anything.

Vapire
  • 4,568
  • 3
  • 24
  • 41
  • Why don't you just use `accesible_by` method? http://stackoverflow.com/questions/5344247/cancan-accessible-by – scaryguy Feb 10 '14 at 09:45