Skip to content

Instantly share code, notes, and snippets.

@emiltin
Created May 18, 2012 08:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save emiltin/2724033 to your computer and use it in GitHub Desktop.
Save emiltin/2724033 to your computer and use it in GitHub Desktop.
cancan authorizing object depening on parent resource
#theme.rb
class Theme < ActiveRecord::Base
belongs_to :challenge
end
#challenge.rb
class Challenge < ActiveRecord::Base
has_many :themes
has_many :roles, :as => :managed, :dependent => :destroy
end
#role.rb
class Role < ActiveRecord::Base
belongs_to :user
belongs_to :managed, :polymorphic => true
end
#user.rb
class User < ActiveRecord::Base
has_many :roles, :dependent => :destroy
end
#ability.rb
class Ability < ActiveRecord::Base
include CanCan::Ability
def initialize(user)
if user
can :manage, Challenge do |challenge|
challenge.roles.exists? :user_id => user.id
end
can :manage, Theme do |theme,challenge|
challenge.roles.exists? :user_id => user.id
end
end
end
end
#routes.rb
Sociallab::Application.routes.draw do
resources :challenges do
resources :themes
end
end
#themes_controller.rb
class ThemesController < ApplicationController
before_filter { @challenge = Challenge.find params[:challenge_id] }
#goal: only allow users to view a theme if she has a role to theme.challenge
def show
@theme = @challenge.themes.find params[:id] #implies @theme.challenge == @challenge
authorize! :show, @theme, @challenge #ok, challenge will be passed as an extra arg to the block in Ability
authorize! :show, @theme #alternatively, we could just pass the theme, and use theme.challenge in the block Ability
end
#goal: only allow users to index themes on a challenge if she has a role to the challenge
def index
authorize! :index, Theme, @challenge #doesn't work, because the block in Ability is not being called when the subject is a class
authorize! :index, Theme #not sufficient, since we need to check if the user has a role to @challenge
authorize! :index_themes, @challenge #this might work, but seems a bit clunky?
@themes = @challenge.themes
end
#goal: only allow users to create a new theme on a challenge if she has a role to the challenge
def new
@theme = @challenge.themes.build #implies @theme.challenge == @challenge
authorize! :new, Theme, @challenge #doesn't work, because the block in Ability is not being called when the subject is a class
authorize! :new, @theme, @challenge #works, but impractical to move to a before_filter since it depends on @theme
authorize! :new, Theme #not sufficient, since we need to check if the user has a role to @challenge
authorize! :manage, @challenge #insufficient as soon as we need different permissions on Challenges and Themes
authorize! :new_theme, @challenge #this might work, but seems a bit clunky?
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment