Skip to content

Instantly share code, notes, and snippets.

@mrflip
Created October 10, 2009 01:57
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 mrflip/206522 to your computer and use it in GitHub Desktop.
Save mrflip/206522 to your computer and use it in GitHub Desktop.
ActiveRecord::Base.class_eval do
# Decide what actions are allowed
# By default, deny all and let models whitelist
def self.authorizes? action, resource=nil
false
end
# Decide what actions are allowed on this model
# By default, objects delegate the decision to their model
def authorizes? action
self.class.authorizes? action, self
end
end
class ApplicationController < ActionController::Base
before_filter :authorize
# Base case: ask the controller's default model if this action is allowed
# Controllers should a prepend_before_filter to set the @resource
def authorize
unless controller_model.authorizes?(params[:action].to_sym, @resource)
respond_to_unauthorized(@resource)
end
end
# Default model for this controller: eg. ClientsController => Client
def controller_model
params[:controller].to_s.classify.constantize
end
#
# Handle an unauthorized request
#
def respond_to_unauthorized resource=nil, options={}, &block
flash[:error] = "Sorry, <a href='/login'>log in</a> first or contact <a href='mailto:help@infochimps.org'>help@infochimps.org</a> for help with [#{params[:action]} #{controller_model}]"
respond_to do |format|
yield format if block
format.html do
redirect_to(resource || root_path)
end
format.xml { head :unauthorized }
format.json { head :unauthorized }
format.yaml { head :unauthorized }
end
end
end
class Client < ActiveRecord::Base
belongs_to :owner, :class_name => 'User'
def self.authorizes? action, resource=nil
case action
when :index then User.logged_in? # users can list their own clients
when :index_all then User.is_admin? # admins can list clients from all users
when :new, :create then User.logged_in?
when :show, :edit, :update then User.admin_or_owns?(resource)
when :destroy then User.owns?(resource)
else false
end
end
end
class ClientController < ActionController::Base
prepend_before_filter :find_from_params, :only => [:show, :edit, :update, :destroy]
# list current_user's clients
def index
@clients = Client.find(:all, :owner => current_user)
end
# list all clients for every user
def index_all
@clients = Client.find(:all)
render 'index'
end
# ... and so forth
protected
def find_from_params
@resource = @client = Client.find(params[:id])
end
end
<!-- ... stuff .... -->
<%= link_to('List all clients', all_clients_path) if Client.authorizes?(:index_all) %>
<%= link_to('Edit', edit_client_path(@client)) if @client.authorizes?(:edit) %>
class User < ActiveRecord::Base
acts_as_authentic
has_many :clients
def self.current_user_session
return @current_user_session if defined?(@current_user_session)
@current_user_session = UserSession.find
end
def self.current_user
return @current_user if defined?(@current_user)
@current_user = current_user_session && current_user_session.record
end
def is_current_user?
User.current_user == self
end
def self.logged_in?
!! current_user
end
def self.is_admin?
logged_in? && current_user.admin
end
def self.owns?(resource)
resource && logged_in? && (! resource.owner.blank?) && (current_user == resource.owner)
end
def self.admin_or_owns?(resource)
is_admin? || owns?(resource)
end
# Please note: this method authorizes actions **on** user(s) not **by** user
def self.authorizes? action
return true if User.is_admin? # Admins can do anything
case action
when :new, :create then true # Anyone can join
when :show, :edit, :update then is_current_user? # users can only see & edit themselves
else false
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment