cancan 1.4.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +13 -0
- data/lib/cancan/active_record_additions.rb +1 -1
- data/lib/cancan/can_definition.rb +1 -1
- data/lib/cancan/controller_additions.rb +12 -4
- data/lib/cancan/controller_resource.rb +7 -3
- data/spec/cancan/active_record_additions_spec.rb +2 -0
- data/spec/cancan/controller_additions_spec.rb +2 -2
- data/spec/cancan/controller_resource_spec.rb +55 -30
- data/spec/spec_helper.rb +12 -12
- metadata +20 -4
data/CHANGELOG.rdoc
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
1.4.1 (November 12, 2010)
|
|
2
|
+
|
|
3
|
+
* Renaming skip_authorization to skip_authorization_check - see issue #169
|
|
4
|
+
|
|
5
|
+
* Adding :through_association option to load_resource (thanks hunterae) - see issue #171
|
|
6
|
+
|
|
7
|
+
* The :shallow option now works with the :singleton option (thanks nandalopes) - see issue #187
|
|
8
|
+
|
|
9
|
+
* Play nicely with quick_scopes gem (thanks ramontayag) - see issue #183
|
|
10
|
+
|
|
11
|
+
* Fix odd behavior when "cache_classes = false" (thanks mphalliday) - see issue #174
|
|
12
|
+
|
|
13
|
+
|
|
1
14
|
1.4.0 (October 5, 2010)
|
|
2
15
|
|
|
3
16
|
* Adding Gemfile; to get specs running just +bundle+ and +rake+ - see issue #163
|
|
@@ -21,7 +21,7 @@ module CanCan
|
|
|
21
21
|
# internally uses Ability#conditions method, see that for more information.
|
|
22
22
|
def accessible_by(ability, action = :read)
|
|
23
23
|
query = ability.query(action, self)
|
|
24
|
-
if respond_to? :
|
|
24
|
+
if respond_to?(:where) && respond_to?(:joins)
|
|
25
25
|
where(query.conditions).joins(query.joins)
|
|
26
26
|
else
|
|
27
27
|
scoped(:conditions => query.conditions, :joins => query.joins)
|
|
@@ -97,7 +97,7 @@ module CanCan
|
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
def matches_subject_class?(subject)
|
|
100
|
-
@subjects.any? { |sub| sub.kind_of?(Module) && (subject.kind_of?(sub) || subject.kind_of?(Module) && subject.ancestors.include?(sub)) }
|
|
100
|
+
@subjects.any? { |sub| sub.kind_of?(Module) && (subject.kind_of?(sub) || subject.class.to_s == sub.to_s || subject.kind_of?(Module) && subject.ancestors.include?(sub)) }
|
|
101
101
|
end
|
|
102
102
|
|
|
103
103
|
def matches_conditions_hash?(subject, conditions = @conditions)
|
|
@@ -71,6 +71,10 @@ module CanCan
|
|
|
71
71
|
# [:+through+]
|
|
72
72
|
# Load this resource through another one. This should match the name of the parent instance variable or method.
|
|
73
73
|
#
|
|
74
|
+
# [:+through_association+]
|
|
75
|
+
# The name of the association to fetch the child records through the parent resource. This is normally not needed
|
|
76
|
+
# because it defaults to the pluralized resource name.
|
|
77
|
+
#
|
|
74
78
|
# [:+shallow+]
|
|
75
79
|
# Pass +true+ to allow this resource to be loaded directly when parent is +nil+. Defaults to +false+.
|
|
76
80
|
#
|
|
@@ -172,11 +176,11 @@ module CanCan
|
|
|
172
176
|
#
|
|
173
177
|
# Any arguments are passed to the +after_filter+ it triggers.
|
|
174
178
|
#
|
|
175
|
-
# See
|
|
179
|
+
# See skip_authorization_check to bypass this check on specific controller actions.
|
|
176
180
|
def check_authorization(*args)
|
|
177
181
|
self.after_filter(*args) do |controller|
|
|
178
182
|
unless controller.instance_variable_defined?(:@_authorized)
|
|
179
|
-
raise AuthorizationNotPerformed, "This action failed the check_authorization because it does not authorize_resource. Add
|
|
183
|
+
raise AuthorizationNotPerformed, "This action failed the check_authorization because it does not authorize_resource. Add skip_authorization_check to bypass this check."
|
|
180
184
|
end
|
|
181
185
|
end
|
|
182
186
|
end
|
|
@@ -184,16 +188,20 @@ module CanCan
|
|
|
184
188
|
# Call this in the class of a controller to skip the check_authorization behavior on the actions.
|
|
185
189
|
#
|
|
186
190
|
# class HomeController < ApplicationController
|
|
187
|
-
#
|
|
191
|
+
# skip_authorization_check :only => :index
|
|
188
192
|
# end
|
|
189
193
|
#
|
|
190
194
|
# Any arguments are passed to the +before_filter+ it triggers.
|
|
191
|
-
def
|
|
195
|
+
def skip_authorization_check(*args)
|
|
192
196
|
self.before_filter(*args) do |controller|
|
|
193
197
|
controller.instance_variable_set(:@_authorized, true)
|
|
194
198
|
end
|
|
195
199
|
end
|
|
196
200
|
|
|
201
|
+
def skip_authorization(*args)
|
|
202
|
+
raise ImplementationRemoved, "The CanCan skip_authorization method has been renamed to skip_authorization_check. Please update your code."
|
|
203
|
+
end
|
|
204
|
+
|
|
197
205
|
def cancan_resource_class
|
|
198
206
|
if ancestors.map(&:to_s).include? "InheritedResources::Actions"
|
|
199
207
|
InheritedResource
|
|
@@ -61,7 +61,11 @@ module CanCan
|
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
def build_resource
|
|
64
|
-
|
|
64
|
+
if @options[:singleton] && resource_base.respond_to?("build_#{name}")
|
|
65
|
+
resource = resource_base.send("build_#{name}")
|
|
66
|
+
else
|
|
67
|
+
resource = resource_base.send("new")
|
|
68
|
+
end
|
|
65
69
|
initial_attributes.each do |name, value|
|
|
66
70
|
resource.send("#{name}=", value)
|
|
67
71
|
end
|
|
@@ -74,7 +78,7 @@ module CanCan
|
|
|
74
78
|
end
|
|
75
79
|
|
|
76
80
|
def find_resource
|
|
77
|
-
if @options[:singleton]
|
|
81
|
+
if @options[:singleton] && resource_base.respond_to?(name)
|
|
78
82
|
resource_base.send(name)
|
|
79
83
|
else
|
|
80
84
|
@options[:find_by] ? resource_base.send("find_by_#{@options[:find_by]}!", id_param) : resource_base.find(id_param)
|
|
@@ -132,7 +136,7 @@ module CanCan
|
|
|
132
136
|
def resource_base
|
|
133
137
|
if @options[:through]
|
|
134
138
|
if parent_resource
|
|
135
|
-
@options[:singleton] ? parent_resource : parent_resource.send(name.to_s.pluralize)
|
|
139
|
+
@options[:singleton] ? parent_resource : parent_resource.send(@options[:through_association] || name.to_s.pluralize)
|
|
136
140
|
elsif @options[:shallow]
|
|
137
141
|
resource_class
|
|
138
142
|
else
|
|
@@ -10,12 +10,14 @@ describe CanCan::ActiveRecordAdditions do
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
it "should call where('true=false') when no ability is defined so no records are found" do
|
|
13
|
+
stub(@model_class).joins { true } # just so it responds to .joins as well
|
|
13
14
|
stub(@model_class).where('true=false').stub!.joins(nil) { :no_match }
|
|
14
15
|
@model_class.accessible_by(@ability, :read).should == :no_match
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
it "should call where with matching ability conditions" do
|
|
18
19
|
@ability.can :read, @model_class, :foo => {:bar => 1}
|
|
20
|
+
stub(@model_class).joins { true } # just so it responds to .joins as well
|
|
19
21
|
stub(@model_class).where(:foos => { :bar => 1 }).stub!.joins([:foo]) { :found_records }
|
|
20
22
|
@model_class.accessible_by(@ability, :read).should == :found_records
|
|
21
23
|
end
|
|
@@ -54,9 +54,9 @@ describe CanCan::ControllerAdditions do
|
|
|
54
54
|
@controller_class.load_resource :foo => :bar, :only => [:show, :index]
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
-
it "
|
|
57
|
+
it "skip_authorization_check should set up a before filter which sets @_authorized to true" do
|
|
58
58
|
mock(@controller_class).before_filter(:filter_options) { |options, block| block.call(@controller) }
|
|
59
|
-
@controller_class.
|
|
59
|
+
@controller_class.skip_authorization_check(:filter_options)
|
|
60
60
|
@controller.instance_variable_get(:@_authorized).should be_true
|
|
61
61
|
end
|
|
62
62
|
|
|
@@ -10,11 +10,11 @@ describe CanCan::ControllerResource do
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
it "should load the resource into an instance variable if params[:id] is specified" do
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
project = Project.create!
|
|
14
|
+
@params.merge!(:action => "show", :id => project.id)
|
|
15
15
|
resource = CanCan::ControllerResource.new(@controller)
|
|
16
16
|
resource.load_resource
|
|
17
|
-
@controller.instance_variable_get(:@project).should ==
|
|
17
|
+
@controller.instance_variable_get(:@project).should == project
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
it "should not load resource into an instance variable if already set" do
|
|
@@ -26,19 +26,19 @@ describe CanCan::ControllerResource do
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
it "should properly load resource for namespaced controller" do
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
project = Project.create!
|
|
30
|
+
@params.merge!(:controller => "admin/projects", :action => "show", :id => project.id)
|
|
31
31
|
resource = CanCan::ControllerResource.new(@controller)
|
|
32
32
|
resource.load_resource
|
|
33
|
-
@controller.instance_variable_get(:@project).should ==
|
|
33
|
+
@controller.instance_variable_get(:@project).should == project
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
it "should properly load resource for namespaced controller when using '::' for namespace" do
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
project = Project.create!
|
|
38
|
+
@params.merge!(:controller => "Admin::ProjectsController", :action => "show", :id => project.id)
|
|
39
39
|
resource = CanCan::ControllerResource.new(@controller)
|
|
40
40
|
resource.load_resource
|
|
41
|
-
@controller.instance_variable_get(:@project).should ==
|
|
41
|
+
@controller.instance_variable_get(:@project).should == project
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
it "should build a new resource with hash if params[:id] is not specified" do
|
|
@@ -157,11 +157,11 @@ describe CanCan::ControllerResource do
|
|
|
157
157
|
end
|
|
158
158
|
|
|
159
159
|
it "should load parent resource through proper id parameter" do
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
project = Project.create!
|
|
161
|
+
@params.merge!(:action => "index", :project_id => project.id)
|
|
162
162
|
resource = CanCan::ControllerResource.new(@controller, :project, :parent => true)
|
|
163
163
|
resource.load_resource
|
|
164
|
-
@controller.instance_variable_get(:@project).should ==
|
|
164
|
+
@controller.instance_variable_get(:@project).should == project
|
|
165
165
|
end
|
|
166
166
|
|
|
167
167
|
it "should load resource through the association of another parent resource using instance variable" do
|
|
@@ -174,6 +174,16 @@ describe CanCan::ControllerResource do
|
|
|
174
174
|
@controller.instance_variable_get(:@project).should == :some_project
|
|
175
175
|
end
|
|
176
176
|
|
|
177
|
+
it "should load resource through the custom association name" do
|
|
178
|
+
@params.merge!(:action => "show", :id => 123)
|
|
179
|
+
category = Object.new
|
|
180
|
+
@controller.instance_variable_set(:@category, category)
|
|
181
|
+
stub(category).custom_projects.stub!.find(123) { :some_project }
|
|
182
|
+
resource = CanCan::ControllerResource.new(@controller, :through => :category, :through_association => :custom_projects)
|
|
183
|
+
resource.load_resource
|
|
184
|
+
@controller.instance_variable_get(:@project).should == :some_project
|
|
185
|
+
end
|
|
186
|
+
|
|
177
187
|
it "should load resource through the association of another parent resource using method" do
|
|
178
188
|
@params.merge!(:action => "show", :id => 123)
|
|
179
189
|
category = Object.new
|
|
@@ -185,16 +195,16 @@ describe CanCan::ControllerResource do
|
|
|
185
195
|
end
|
|
186
196
|
|
|
187
197
|
it "should not load through parent resource if instance isn't loaded when shallow" do
|
|
188
|
-
|
|
189
|
-
|
|
198
|
+
project = Project.create!
|
|
199
|
+
@params.merge!(:action => "show", :id => project.id)
|
|
190
200
|
resource = CanCan::ControllerResource.new(@controller, :through => :category, :shallow => true)
|
|
191
201
|
resource.load_resource
|
|
192
|
-
@controller.instance_variable_get(:@project).should ==
|
|
202
|
+
@controller.instance_variable_get(:@project).should == project
|
|
193
203
|
end
|
|
194
204
|
|
|
195
205
|
it "should raise AccessDenied when attempting to load resource through nil" do
|
|
196
|
-
|
|
197
|
-
|
|
206
|
+
project = Project.create!
|
|
207
|
+
@params.merge!(:action => "show", :id => project.id)
|
|
198
208
|
resource = CanCan::ControllerResource.new(@controller, :through => :category)
|
|
199
209
|
lambda {
|
|
200
210
|
resource.load_resource
|
|
@@ -241,20 +251,35 @@ describe CanCan::ControllerResource do
|
|
|
241
251
|
@controller.instance_variable_get(:@project).name.should == "foobar"
|
|
242
252
|
end
|
|
243
253
|
|
|
254
|
+
it "should find record through has_one association with :singleton and :shallow options" do
|
|
255
|
+
project = Project.create!
|
|
256
|
+
@params.merge!(:action => "show", :id => project.id)
|
|
257
|
+
resource = CanCan::ControllerResource.new(@controller, :through => :category, :singleton => true, :shallow => true)
|
|
258
|
+
resource.load_resource
|
|
259
|
+
@controller.instance_variable_get(:@project).should == project
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
it "should build record through has_one association with :singleton and :shallow options" do
|
|
263
|
+
@params.merge!(:action => "create", :project => {:name => "foobar"})
|
|
264
|
+
resource = CanCan::ControllerResource.new(@controller, :through => :category, :singleton => true, :shallow => true)
|
|
265
|
+
resource.load_resource
|
|
266
|
+
@controller.instance_variable_get(:@project).name.should == "foobar"
|
|
267
|
+
end
|
|
268
|
+
|
|
244
269
|
it "should only authorize :read action on parent resource" do
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
stub(@controller).authorize!(:read,
|
|
270
|
+
project = Project.create!
|
|
271
|
+
@params.merge!(:action => "new", :project_id => project.id)
|
|
272
|
+
stub(@controller).authorize!(:read, project) { raise CanCan::AccessDenied }
|
|
248
273
|
resource = CanCan::ControllerResource.new(@controller, :project, :parent => true)
|
|
249
274
|
lambda { resource.load_and_authorize_resource }.should raise_error(CanCan::AccessDenied)
|
|
250
275
|
end
|
|
251
276
|
|
|
252
277
|
it "should load the model using a custom class" do
|
|
253
|
-
|
|
254
|
-
|
|
278
|
+
project = Project.create!
|
|
279
|
+
@params.merge!(:action => "show", :id => project.id)
|
|
255
280
|
resource = CanCan::ControllerResource.new(@controller, :class => Project)
|
|
256
281
|
resource.load_resource
|
|
257
|
-
@controller.instance_variable_get(:@project).should ==
|
|
282
|
+
@controller.instance_variable_get(:@project).should == project
|
|
258
283
|
end
|
|
259
284
|
|
|
260
285
|
it "should authorize based on resource name if class is false" do
|
|
@@ -265,20 +290,20 @@ describe CanCan::ControllerResource do
|
|
|
265
290
|
end
|
|
266
291
|
|
|
267
292
|
it "should load and authorize using custom instance name" do
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
stub(@controller).authorize!(:show,
|
|
293
|
+
project = Project.create!
|
|
294
|
+
@params.merge!(:action => "show", :id => project.id)
|
|
295
|
+
stub(@controller).authorize!(:show, project) { raise CanCan::AccessDenied }
|
|
271
296
|
resource = CanCan::ControllerResource.new(@controller, :instance_name => :custom_project)
|
|
272
297
|
lambda { resource.load_and_authorize_resource }.should raise_error(CanCan::AccessDenied)
|
|
273
|
-
@controller.instance_variable_get(:@custom_project).should ==
|
|
298
|
+
@controller.instance_variable_get(:@custom_project).should == project
|
|
274
299
|
end
|
|
275
300
|
|
|
276
301
|
it "should load resource using custom find_by attribute" do
|
|
277
|
-
|
|
278
|
-
|
|
302
|
+
project = Project.create!(:name => "foo")
|
|
303
|
+
@params.merge!(:action => "show", :id => "foo")
|
|
279
304
|
resource = CanCan::ControllerResource.new(@controller, :find_by => :name)
|
|
280
305
|
resource.load_resource
|
|
281
|
-
@controller.instance_variable_get(:@project).should ==
|
|
306
|
+
@controller.instance_variable_get(:@project).should == project
|
|
282
307
|
end
|
|
283
308
|
|
|
284
309
|
it "should raise ImplementationRemoved when adding :name option" do
|
data/spec/spec_helper.rb
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
require 'rubygems'
|
|
2
|
-
require 'bundler'
|
|
3
|
-
Bundler.require(:default
|
|
2
|
+
require 'bundler/setup'
|
|
3
|
+
Bundler.require(:default)
|
|
4
|
+
require 'supermodel' # shouldn't Bundler do this already?
|
|
4
5
|
require 'active_support/all'
|
|
5
6
|
require 'matchers'
|
|
6
7
|
require 'cancan/matchers'
|
|
7
8
|
|
|
8
9
|
RSpec.configure do |config|
|
|
9
10
|
config.mock_with :rr
|
|
11
|
+
config.before(:each) do
|
|
12
|
+
Project.delete_all
|
|
13
|
+
Category.delete_all
|
|
14
|
+
end
|
|
10
15
|
end
|
|
11
16
|
|
|
12
17
|
class Ability
|
|
@@ -16,17 +21,12 @@ class Ability
|
|
|
16
21
|
end
|
|
17
22
|
end
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def initialize(attributes = {})
|
|
24
|
-
@name = attributes[:name]
|
|
25
|
-
end
|
|
24
|
+
class Category < SuperModel::Base
|
|
25
|
+
has_many :projects
|
|
26
|
+
end
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
end
|
|
28
|
+
class Project < SuperModel::Base
|
|
29
|
+
belongs_to :category
|
|
30
30
|
|
|
31
31
|
class << self
|
|
32
32
|
protected
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cancan
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
hash:
|
|
4
|
+
hash: 5
|
|
5
5
|
prerelease: false
|
|
6
6
|
segments:
|
|
7
7
|
- 1
|
|
8
8
|
- 4
|
|
9
|
-
-
|
|
10
|
-
version: 1.4.
|
|
9
|
+
- 1
|
|
10
|
+
version: 1.4.1
|
|
11
11
|
platform: ruby
|
|
12
12
|
authors:
|
|
13
13
|
- Ryan Bates
|
|
@@ -15,7 +15,7 @@ autorequire:
|
|
|
15
15
|
bindir: bin
|
|
16
16
|
cert_chain: []
|
|
17
17
|
|
|
18
|
-
date: 2010-
|
|
18
|
+
date: 2010-11-12 00:00:00 -08:00
|
|
19
19
|
default_executable:
|
|
20
20
|
dependencies:
|
|
21
21
|
- !ruby/object:Gem::Dependency
|
|
@@ -68,6 +68,22 @@ dependencies:
|
|
|
68
68
|
version: 0.10.11
|
|
69
69
|
type: :development
|
|
70
70
|
version_requirements: *id003
|
|
71
|
+
- !ruby/object:Gem::Dependency
|
|
72
|
+
name: supermodel
|
|
73
|
+
prerelease: false
|
|
74
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
|
75
|
+
none: false
|
|
76
|
+
requirements:
|
|
77
|
+
- - ~>
|
|
78
|
+
- !ruby/object:Gem::Version
|
|
79
|
+
hash: 19
|
|
80
|
+
segments:
|
|
81
|
+
- 0
|
|
82
|
+
- 1
|
|
83
|
+
- 4
|
|
84
|
+
version: 0.1.4
|
|
85
|
+
type: :development
|
|
86
|
+
version_requirements: *id004
|
|
71
87
|
description: Simple authorization solution for Rails which is decoupled from user roles. All permissions are stored in a single location.
|
|
72
88
|
email: ryan@railscasts.com
|
|
73
89
|
executables: []
|