Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
929579f03b | ||
|
|
f9ad4858f5 | ||
|
|
5c4c179c5a | ||
|
|
78cbea5733 | ||
|
|
cff922915e | ||
|
|
2012311c40 | ||
|
|
55c8a5045b | ||
|
|
344832d199 | ||
|
|
52b33589dc |
@@ -1,3 +1,10 @@
|
||||
1.5.1 (January 20, 2011)
|
||||
|
||||
* Fixing deeply nested conditions in Active Record adapter - see issue #246
|
||||
|
||||
* Improving Mongoid support for multiple can and cannot definitions (thanks stellard) - see issue #239
|
||||
|
||||
|
||||
1.5.0 (January 11, 2011)
|
||||
|
||||
* Added an Ability generator - see issue #170
|
||||
|
||||
2
Gemfile
2
Gemfile
@@ -11,7 +11,7 @@ when "data_mapper"
|
||||
gem "dm-migrations", "~> 1.0.2"
|
||||
when "mongoid"
|
||||
gem "bson_ext", "~> 1.1"
|
||||
gem "mongoid", "~> 2.0.0.beta.19"
|
||||
gem "mongoid", "~> 2.0.0.beta.20"
|
||||
else
|
||||
raise "Unknown model adapter: #{ENV["MODEL_ADAPTER"]}"
|
||||
end
|
||||
|
||||
25
README.rdoc
25
README.rdoc
@@ -7,7 +7,7 @@ CanCan is an authorization library for Ruby on Rails which restricts what resour
|
||||
|
||||
== Installation
|
||||
|
||||
In <b>Rails 3</b>, add this to your Gemfile.
|
||||
In <b>Rails 3</b>, add this to your Gemfile and run the +bundle+ command.
|
||||
|
||||
gem "cancan"
|
||||
|
||||
@@ -22,13 +22,19 @@ Alternatively, you can install it as a plugin.
|
||||
|
||||
== Getting Started
|
||||
|
||||
CanCan expects a +current_user+ method to exist in controllers. First, set up some authentication (such as Authlogic[https://github.com/binarylogic/authlogic] or Devise[https://github.com/plataformatec/devise]). See {Changing Defaults}[https://github.com/ryanb/cancan/wiki/changing-defaults] if you need to customize this behavior.
|
||||
CanCan expects a +current_user+ method to exist in the controller. First, set up some authentication (such as Authlogic[https://github.com/binarylogic/authlogic] or Devise[https://github.com/plataformatec/devise]). See {Changing Defaults}[https://github.com/ryanb/cancan/wiki/changing-defaults] if you need different behavior.
|
||||
|
||||
Next, make an +Ability+ class. CanCan 1.5 includes a generator for this.
|
||||
|
||||
=== 1. Define Abilities
|
||||
|
||||
User permissions are defined in an +Ability+ class. CanCan 1.5 includes a Rails 3 generator for creating this class.
|
||||
|
||||
rails g cancan:ability
|
||||
|
||||
This is where the user permission will be defined. See the comments in models/ability.rb and {Defining Abilities}[https://github.com/ryanb/cancan/wiki/defining-abilities] for details.
|
||||
See {Defining Abilities}[https://github.com/ryanb/cancan/wiki/defining-abilities] for details.
|
||||
|
||||
|
||||
=== 2. Check Abilities & Authorization
|
||||
|
||||
The current user's permissions can then be checked using the <tt>can?</tt> and <tt>cannot?</tt> methods in the view and controller.
|
||||
|
||||
@@ -38,14 +44,14 @@ The current user's permissions can then be checked using the <tt>can?</tt> and <
|
||||
|
||||
See {Checking Abilities}[https://github.com/ryanb/cancan/wiki/checking-abilities] for more information
|
||||
|
||||
The "authorize!" method in the controller will raise an exception if the user is not able to perform the given action.
|
||||
The <tt>authorize!</tt> method in the controller will raise an exception if the user is not able to perform the given action.
|
||||
|
||||
def show
|
||||
@article = Article.find(params[:id])
|
||||
authorize! :read, @article
|
||||
end
|
||||
|
||||
Setting this for every action can be tedious, therefore the +load_and_authorize_resource+ method is provided to automatically authorize all actions in a RESTful style resource controller. It will use a before filter to load the resource into an instance variable and authorize it for each action.
|
||||
Setting this for every action can be tedious, therefore the +load_and_authorize_resource+ method is provided to automatically authorize all actions in a RESTful style resource controller. It will use a before filter to load the resource into an instance variable and authorize it for every action.
|
||||
|
||||
class ArticlesController < ApplicationController
|
||||
load_and_authorize_resource
|
||||
@@ -57,6 +63,9 @@ Setting this for every action can be tedious, therefore the +load_and_authorize_
|
||||
|
||||
See {Authorizing Controller Actions}[https://github.com/ryanb/cancan/wiki/authorizing-controller-actions] for more information.
|
||||
|
||||
|
||||
=== 3. Handle Unauthorized Access
|
||||
|
||||
If the user authorization fails, a <tt>CanCan::AccessDenied</tt> exception will be raised. You can catch this and modify its behavior in the +ApplicationController+.
|
||||
|
||||
class ApplicationController < ActionController::Base
|
||||
@@ -82,9 +91,9 @@ See {Exception Handling}[https://github.com/ryanb/cancan/wiki/exception-handling
|
||||
|
||||
== Questions or Problems?
|
||||
|
||||
If you have any issues with CanCan which you cannot find the solution to in the documentation, please add an {issue on GitHub}[https://github.com/ryanb/cancan/issues] or fork the project and send a pull request.
|
||||
If you have any issues with CanCan which you cannot find the solution to in the documentation[https://github.com/ryanb/cancan/wiki], please add an {issue on GitHub}[https://github.com/ryanb/cancan/issues] or fork the project and send a pull request.
|
||||
|
||||
To get the specs running you should call +bundle+ and then +rake+. Specs currently do not work in Ruby 1.9 due to the RR mocking framework. See the {spec/README}[https://github.com/ryanb/cancan/blob/master/spec/README.rdoc] for more information.
|
||||
To get the specs running you should call +bundle+ and then +rake+. See the {spec/README}[https://github.com/ryanb/cancan/blob/master/spec/README.rdoc] for more information.
|
||||
|
||||
|
||||
== Special Thanks
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "cancan"
|
||||
s.version = "1.5.0"
|
||||
s.version = "1.5.1"
|
||||
s.author = "Ryan Bates"
|
||||
s.email = "ryan@railscasts.com"
|
||||
s.homepage = "http://github.com/ryanb/cancan"
|
||||
|
||||
@@ -294,7 +294,7 @@ module CanCan
|
||||
#
|
||||
# class ApplicationController < ActionController::Base
|
||||
# rescue_from CanCan::AccessDenied do |exception|
|
||||
# flash[:error] = exception.message
|
||||
# flash[:alert] = exception.message
|
||||
# redirect_to root_url
|
||||
# end
|
||||
# end
|
||||
|
||||
@@ -31,12 +31,13 @@ module CanCan
|
||||
end
|
||||
end
|
||||
|
||||
def tableized_conditions(conditions)
|
||||
def tableized_conditions(conditions, model_class = @model_class)
|
||||
return conditions unless conditions.kind_of? Hash
|
||||
conditions.inject({}) do |result_hash, (name, value)|
|
||||
if value.kind_of? Hash
|
||||
name = @model_class.reflect_on_association(name).table_name
|
||||
value = tableized_conditions(value)
|
||||
association_class = model_class.reflect_on_association(name).class_name.constantize
|
||||
name = model_class.reflect_on_association(name).table_name
|
||||
value = tableized_conditions(value, association_class)
|
||||
end
|
||||
result_hash[name] = value
|
||||
result_hash
|
||||
|
||||
@@ -16,21 +16,18 @@ module CanCan
|
||||
end
|
||||
|
||||
def database_records
|
||||
@model_class.where(conditions)
|
||||
end
|
||||
|
||||
def conditions
|
||||
if @rules.size == 0
|
||||
false_query
|
||||
if @rules.size == 0
|
||||
@model_class.where(:_id => {'$exists' => false, '$type' => 7}) # return no records in Mongoid
|
||||
else
|
||||
@rules.first.conditions
|
||||
@rules.inject(@model_class.all) do |records, rule|
|
||||
if rule.base_behavior
|
||||
records.or(rule.conditions)
|
||||
else
|
||||
records.excludes(rule.conditions)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def false_query
|
||||
# this query is sure to return no results
|
||||
{:_id => {'$exists' => false, '$type' => 7}} # type 7 is an ObjectID (default for _id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,12 +8,23 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
|
||||
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
||||
|
||||
describe CanCan::ModelAdapters::ActiveRecordAdapter do
|
||||
with_model :category do
|
||||
table do |t|
|
||||
t.boolean "visible"
|
||||
end
|
||||
model do
|
||||
has_many :articles
|
||||
end
|
||||
end
|
||||
|
||||
with_model :article do
|
||||
table do |t|
|
||||
t.boolean "published"
|
||||
t.boolean "secret"
|
||||
t.integer "category_id"
|
||||
end
|
||||
model do
|
||||
belongs_to :category
|
||||
has_many :comments
|
||||
end
|
||||
end
|
||||
@@ -88,6 +99,13 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
|
||||
Comment.accessible_by(@ability).should == [comment1]
|
||||
end
|
||||
|
||||
it "should only read comments for visible categories through articles" do
|
||||
@ability.can :read, Comment, :article => { :category => { :visible => true } }
|
||||
comment1 = Comment.create!(:article => Article.create!(:category => Category.create!(:visible => true)))
|
||||
comment2 = Comment.create!(:article => Article.create!(:category => Category.create!(:visible => false)))
|
||||
Comment.accessible_by(@ability).should == [comment1]
|
||||
end
|
||||
|
||||
it "should allow conditions in SQL and merge with hash conditions" do
|
||||
@ability.can :read, Article, :published => true
|
||||
@ability.can :read, Article, ["secret=?", true]
|
||||
|
||||
@@ -56,7 +56,7 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
|
||||
lord = MongoidProject.create(:title => 'Lord')
|
||||
dude = MongoidProject.create(:title => 'Dude')
|
||||
|
||||
MongoidProject.accessible_by(@ability, :read).should == [sir]
|
||||
MongoidProject.accessible_by(@ability, :read).entries.should == [sir]
|
||||
end
|
||||
|
||||
it "should return everything when the defined ability is manage all" do
|
||||
@@ -154,7 +154,24 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
|
||||
@ability.can :read, MongoidProject, :foo => {:bar => 1}
|
||||
MongoidProject.accessible_by(@ability, :read).entries.first.should == obj
|
||||
end
|
||||
|
||||
it "should exclude from the result if set to cannot" do
|
||||
obj = MongoidProject.create(:bar => 1)
|
||||
obj2 = MongoidProject.create(:bar => 2)
|
||||
@ability.can :read, MongoidProject
|
||||
@ability.cannot :read, MongoidProject, :bar => 2
|
||||
MongoidProject.accessible_by(@ability, :read).entries.should == [obj]
|
||||
end
|
||||
|
||||
it "should combine the rules" do
|
||||
obj = MongoidProject.create(:bar => 1)
|
||||
obj2 = MongoidProject.create(:bar => 2)
|
||||
obj3 = MongoidProject.create(:bar => 3)
|
||||
@ability.can :read, MongoidProject, :bar => 1
|
||||
@ability.can :read, MongoidProject, :bar => 2
|
||||
MongoidProject.accessible_by(@ability, :read).entries.should =~ [obj, obj2]
|
||||
end
|
||||
|
||||
it "should not allow to fetch records when ability with just block present" do
|
||||
@ability.can :read, MongoidProject do
|
||||
false
|
||||
|
||||
Reference in New Issue
Block a user