cancan 1.6.5 → 1.6.7
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 +24 -1
- data/Gemfile +2 -2
- data/lib/cancan/controller_additions.rb +5 -5
- data/lib/cancan/controller_resource.rb +26 -4
- data/lib/cancan/exceptions.rb +1 -1
- data/lib/cancan/matchers.rb +2 -2
- data/lib/cancan/model_adapters/abstract_adapter.rb +5 -0
- data/lib/cancan/model_adapters/data_mapper_adapter.rb +5 -3
- data/spec/cancan/controller_resource_spec.rb +31 -3
- data/spec/cancan/exceptions_spec.rb +23 -0
- data/spec/cancan/model_adapters/active_record_adapter_spec.rb +5 -4
- data/spec/cancan/model_adapters/data_mapper_adapter_spec.rb +5 -0
- data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +5 -0
- data/spec/spec_helper.rb +12 -0
- metadata +11 -13
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,27 @@
|
|
1
|
+
1.6.7 (October 4, 2011)
|
2
|
+
|
3
|
+
* fixing nested resource problem caused by namespace addition - issue #482
|
4
|
+
|
5
|
+
|
6
|
+
1.6.6 (September 28, 2011)
|
7
|
+
|
8
|
+
* correct "return cant jump across threads" error when using check_authorization (thanks codeprimate) - issues #463, #469
|
9
|
+
|
10
|
+
* fixing tests in development by specifying with_model version (thanks kirkconnell) - issue #476
|
11
|
+
|
12
|
+
* added travis.yml file for TravisCI support (thanks bai) - issue #427
|
13
|
+
|
14
|
+
* better support for namespaced models (thanks whilefalse) - issues #424
|
15
|
+
|
16
|
+
* adding :id_param option to load_and_authorize_resource (thanks skhisma) - issue #425
|
17
|
+
|
18
|
+
* make default unauthorized message translatable text (thanks nhocki) - issue #409
|
19
|
+
|
20
|
+
* improving DataMapper behavior (thanks psanford, maxsum-corin) - issue #410, #373
|
21
|
+
|
22
|
+
* allow :find_by option to be full find method name - issue #335
|
23
|
+
|
24
|
+
|
1
25
|
1.6.5 (May 18, 2011)
|
2
26
|
|
3
27
|
* pass action and subject through AccessDenied exception when :through isn't found - issue #366
|
@@ -15,7 +39,6 @@
|
|
15
39
|
* improve scope merging - issue #328
|
16
40
|
|
17
41
|
|
18
|
-
|
19
42
|
1.6.4 (March 29, 2011)
|
20
43
|
|
21
44
|
* Fixed mongoid 'or' error - see issue #322
|
data/Gemfile
CHANGED
@@ -3,8 +3,8 @@ source "http://rubygems.org"
|
|
3
3
|
case ENV["MODEL_ADAPTER"]
|
4
4
|
when nil, "active_record"
|
5
5
|
gem "sqlite3"
|
6
|
-
gem "activerecord", :require => "active_record"
|
7
|
-
gem "with_model"
|
6
|
+
gem "activerecord", '~> 3.0.9', :require => "active_record"
|
7
|
+
gem "with_model", '~> 0.1.5'
|
8
8
|
gem "meta_where"
|
9
9
|
when "data_mapper"
|
10
10
|
gem "dm-core", "~> 1.0.2"
|
@@ -186,7 +186,7 @@ module CanCan
|
|
186
186
|
skip_authorize_resource(*args)
|
187
187
|
end
|
188
188
|
|
189
|
-
# Skip
|
189
|
+
# Skip the loading behavior of CanCan. This is useful when using +load_and_authorize_resource+ but want to
|
190
190
|
# only do authorization on certain actions. You can pass :only and :except options to specify which actions to
|
191
191
|
# skip the effects on. It will apply to all actions by default.
|
192
192
|
#
|
@@ -202,7 +202,7 @@ module CanCan
|
|
202
202
|
cancan_skipper[:load][name] = options
|
203
203
|
end
|
204
204
|
|
205
|
-
# Skip
|
205
|
+
# Skip the authorization behavior of CanCan. This is useful when using +load_and_authorize_resource+ but want to
|
206
206
|
# only do loading on certain actions. You can pass :only and :except options to specify which actions to
|
207
207
|
# skip the effects on. It will apply to all actions by default.
|
208
208
|
#
|
@@ -247,9 +247,9 @@ module CanCan
|
|
247
247
|
#
|
248
248
|
def check_authorization(options = {})
|
249
249
|
self.after_filter(options.slice(:only, :except)) do |controller|
|
250
|
-
|
251
|
-
|
252
|
-
|
250
|
+
next if controller.instance_variable_defined?(:@_authorized)
|
251
|
+
next if options[:if] && !controller.send(options[:if])
|
252
|
+
next if options[:unless] && controller.send(options[:unless])
|
253
253
|
raise AuthorizationNotPerformed, "This action failed the check_authorization because it does not authorize_resource. Add skip_authorization_check to bypass this check."
|
254
254
|
end
|
255
255
|
end
|
@@ -100,20 +100,36 @@ module CanCan
|
|
100
100
|
if @options[:singleton] && parent_resource.respond_to?(name)
|
101
101
|
parent_resource.send(name)
|
102
102
|
else
|
103
|
-
|
103
|
+
if @options[:find_by]
|
104
|
+
if resource_base.respond_to? "find_by_#{@options[:find_by]}!"
|
105
|
+
resource_base.send("find_by_#{@options[:find_by]}!", id_param)
|
106
|
+
else
|
107
|
+
resource_base.send(@options[:find_by], id_param)
|
108
|
+
end
|
109
|
+
else
|
110
|
+
adapter.find(resource_base, id_param)
|
111
|
+
end
|
104
112
|
end
|
105
113
|
end
|
106
114
|
|
115
|
+
def adapter
|
116
|
+
ModelAdapters::AbstractAdapter.adapter_class(resource_class)
|
117
|
+
end
|
118
|
+
|
107
119
|
def authorization_action
|
108
120
|
parent? ? :show : @params[:action].to_sym
|
109
121
|
end
|
110
122
|
|
111
123
|
def id_param
|
112
|
-
@
|
124
|
+
if @options[:id_param]
|
125
|
+
@params[@options[:id_param]]
|
126
|
+
else
|
127
|
+
@params[parent? ? :"#{name}_id" : :id]
|
128
|
+
end
|
113
129
|
end
|
114
130
|
|
115
131
|
def member_action?
|
116
|
-
new_actions.include?(@params[:action].to_sym) || @options[:singleton] || (@params[:id] && !collection_actions.include?(@params[:action].to_sym))
|
132
|
+
new_actions.include?(@params[:action].to_sym) || @options[:singleton] || ( (@params[:id] || @params[@options[:id_param]]) && !collection_actions.include?(@params[:action].to_sym))
|
117
133
|
end
|
118
134
|
|
119
135
|
# Returns the class used for this resource. This can be overriden by the :class option.
|
@@ -122,7 +138,7 @@ module CanCan
|
|
122
138
|
def resource_class
|
123
139
|
case @options[:class]
|
124
140
|
when false then name.to_sym
|
125
|
-
when nil then
|
141
|
+
when nil then namespaced_name.to_s.camelize.constantize
|
126
142
|
when String then @options[:class].constantize
|
127
143
|
else @options[:class]
|
128
144
|
end
|
@@ -191,6 +207,12 @@ module CanCan
|
|
191
207
|
@name || name_from_controller
|
192
208
|
end
|
193
209
|
|
210
|
+
def namespaced_name
|
211
|
+
@name || @params[:controller].sub("Controller", "").singularize.camelize.constantize
|
212
|
+
rescue NameError
|
213
|
+
name
|
214
|
+
end
|
215
|
+
|
194
216
|
def name_from_controller
|
195
217
|
@params[:controller].sub("Controller", "").underscore.split('/').last.singularize
|
196
218
|
end
|
data/lib/cancan/exceptions.rb
CHANGED
@@ -40,7 +40,7 @@ module CanCan
|
|
40
40
|
@message = message
|
41
41
|
@action = action
|
42
42
|
@subject = subject
|
43
|
-
@default_message = "You are not authorized to access this page."
|
43
|
+
@default_message = I18n.t(:"unauthorized.default", :default => "You are not authorized to access this page.")
|
44
44
|
end
|
45
45
|
|
46
46
|
def to_s
|
data/lib/cancan/matchers.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
rspec_module = defined?(RSpec::Core) ? 'RSpec' : 'Spec' # for RSpec 1 compatability
|
2
|
+
Kernel.const_get(rspec_module)::Matchers.define :be_able_to do |*args|
|
3
3
|
match do |ability|
|
4
4
|
ability.can?(*args)
|
5
5
|
end
|
@@ -15,6 +15,11 @@ module CanCan
|
|
15
15
|
false # override in subclass
|
16
16
|
end
|
17
17
|
|
18
|
+
# Override if you need custom find behavior
|
19
|
+
def self.find(model_class, id)
|
20
|
+
model_class.find(id)
|
21
|
+
end
|
22
|
+
|
18
23
|
# Used to determine if this model adapter will override the matching behavior for a hash of conditions.
|
19
24
|
# If this returns true then matches_conditions_hash? will be called. See Rule#matches_conditions_hash
|
20
25
|
def self.override_conditions_hash_matching?(subject, conditions)
|
@@ -5,6 +5,10 @@ module CanCan
|
|
5
5
|
model_class <= DataMapper::Resource
|
6
6
|
end
|
7
7
|
|
8
|
+
def self.find(model_class, id)
|
9
|
+
model_class.get(id)
|
10
|
+
end
|
11
|
+
|
8
12
|
def self.override_conditions_hash_matching?(subject, conditions)
|
9
13
|
conditions.any? { |k,v| !k.kind_of?(Symbol) }
|
10
14
|
end
|
@@ -27,6 +31,4 @@ module CanCan
|
|
27
31
|
end # module ModelAdapters
|
28
32
|
end # module CanCan
|
29
33
|
|
30
|
-
DataMapper::Model.
|
31
|
-
include CanCan::ModelAdditions::ClassMethods
|
32
|
-
end
|
34
|
+
DataMapper::Model.append_extensions(CanCan::ModelAdditions::ClassMethods)
|
@@ -35,6 +35,18 @@ describe CanCan::ControllerResource do
|
|
35
35
|
@controller.instance_variable_get(:@project).should == project
|
36
36
|
end
|
37
37
|
|
38
|
+
it "should attempt to load a resource with the same namespace as the controller when using :: for namespace" do
|
39
|
+
module MyEngine
|
40
|
+
class Project < ::Project; end
|
41
|
+
end
|
42
|
+
|
43
|
+
project = MyEngine::Project.create!
|
44
|
+
@params.merge!(:controller => "MyEngine::ProjectsController", :action => "show", :id => project.id)
|
45
|
+
resource = CanCan::ControllerResource.new(@controller)
|
46
|
+
resource.load_resource
|
47
|
+
@controller.instance_variable_get(:@project).should == project
|
48
|
+
end
|
49
|
+
|
38
50
|
it "should properly load resource for namespaced controller when using '::' for namespace" do
|
39
51
|
project = Project.create!
|
40
52
|
@params.merge!(:controller => "Admin::ProjectsController", :action => "show", :id => project.id)
|
@@ -185,8 +197,8 @@ describe CanCan::ControllerResource do
|
|
185
197
|
|
186
198
|
it "should load parent resource through proper id parameter" do
|
187
199
|
project = Project.create!
|
188
|
-
@params.merge!(:action => "index", :project_id => project.id)
|
189
|
-
resource = CanCan::ControllerResource.new(@controller, :project
|
200
|
+
@params.merge!(:controller => "categories", :action => "index", :project_id => project.id)
|
201
|
+
resource = CanCan::ControllerResource.new(@controller, :project)
|
190
202
|
resource.load_resource
|
191
203
|
@controller.instance_variable_get(:@project).should == project
|
192
204
|
end
|
@@ -327,7 +339,15 @@ describe CanCan::ControllerResource do
|
|
327
339
|
lambda { resource.load_and_authorize_resource }.should raise_error(CanCan::AccessDenied)
|
328
340
|
@controller.instance_variable_get(:@custom_project).should == project
|
329
341
|
end
|
330
|
-
|
342
|
+
|
343
|
+
it "should load resource using custom ID param" do
|
344
|
+
project = Project.create!
|
345
|
+
@params.merge!(:action => "show", :the_project => project.id)
|
346
|
+
resource = CanCan::ControllerResource.new(@controller, :id_param => :the_project)
|
347
|
+
resource.load_resource
|
348
|
+
@controller.instance_variable_get(:@project).should == project
|
349
|
+
end
|
350
|
+
|
331
351
|
it "should load resource using custom find_by attribute" do
|
332
352
|
project = Project.create!(:name => "foo")
|
333
353
|
@params.merge!(:action => "show", :id => "foo")
|
@@ -336,6 +356,14 @@ describe CanCan::ControllerResource do
|
|
336
356
|
@controller.instance_variable_get(:@project).should == project
|
337
357
|
end
|
338
358
|
|
359
|
+
it "should allow full find method to be passed into find_by option" do
|
360
|
+
project = Project.create!(:name => "foo")
|
361
|
+
@params.merge!(:action => "show", :id => "foo")
|
362
|
+
resource = CanCan::ControllerResource.new(@controller, :find_by => :find_by_name)
|
363
|
+
resource.load_resource
|
364
|
+
@controller.instance_variable_get(:@project).should == project
|
365
|
+
end
|
366
|
+
|
339
367
|
it "should raise ImplementationRemoved when adding :name option" do
|
340
368
|
lambda {
|
341
369
|
CanCan::ControllerResource.new(@controller, :name => :foo)
|
@@ -32,4 +32,27 @@ describe CanCan::AccessDenied do
|
|
32
32
|
@exception.message.should == "Access denied!"
|
33
33
|
end
|
34
34
|
end
|
35
|
+
|
36
|
+
describe "i18n in the default message" do
|
37
|
+
after(:each) do
|
38
|
+
I18n.backend = nil
|
39
|
+
end
|
40
|
+
|
41
|
+
it "uses i18n for the default message" do
|
42
|
+
I18n.backend.store_translations :en, :unauthorized => {:default => "This is a different message"}
|
43
|
+
@exception = CanCan::AccessDenied.new
|
44
|
+
@exception.message.should == "This is a different message"
|
45
|
+
end
|
46
|
+
|
47
|
+
it "defaults to a nice message" do
|
48
|
+
@exception = CanCan::AccessDenied.new
|
49
|
+
@exception.message.should == "You are not authorized to access this page."
|
50
|
+
end
|
51
|
+
|
52
|
+
it "does not use translation if a message is given" do
|
53
|
+
@exception = CanCan::AccessDenied.new("Hey! You're not welcome here")
|
54
|
+
@exception.message.should == "Hey! You're not welcome here"
|
55
|
+
@exception.message.should_not == "You are not authorized to access this page."
|
56
|
+
end
|
57
|
+
end
|
35
58
|
end
|
@@ -1,10 +1,6 @@
|
|
1
1
|
if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
|
2
2
|
require "spec_helper"
|
3
3
|
|
4
|
-
RSpec.configure do |config|
|
5
|
-
config.extend WithModel
|
6
|
-
end
|
7
|
-
|
8
4
|
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
9
5
|
|
10
6
|
describe CanCan::ModelAdapters::ActiveRecordAdapter do
|
@@ -56,6 +52,11 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
|
|
56
52
|
CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article).should == CanCan::ModelAdapters::ActiveRecordAdapter
|
57
53
|
end
|
58
54
|
|
55
|
+
it "should find record" do
|
56
|
+
article = Article.create!
|
57
|
+
CanCan::ModelAdapters::ActiveRecordAdapter.find(Article, article.id).should == article
|
58
|
+
end
|
59
|
+
|
59
60
|
it "should not fetch any records when no abilities are defined" do
|
60
61
|
Article.create!
|
61
62
|
Article.accessible_by(@ability).should be_empty
|
@@ -36,6 +36,11 @@ if ENV["MODEL_ADAPTER"] == "data_mapper"
|
|
36
36
|
CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article).should == CanCan::ModelAdapters::DataMapperAdapter
|
37
37
|
end
|
38
38
|
|
39
|
+
it "should find record" do
|
40
|
+
article = Article.create
|
41
|
+
CanCan::ModelAdapters::DataMapperAdapter.find(Article, article.id).should == article
|
42
|
+
end
|
43
|
+
|
39
44
|
it "should not fetch any records when no abilities are defined" do
|
40
45
|
Article.create
|
41
46
|
Article.accessible_by(@ability).should be_empty
|
@@ -36,6 +36,11 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
|
|
36
36
|
CanCan::ModelAdapters::AbstractAdapter.adapter_class(MongoidProject).should == CanCan::ModelAdapters::MongoidAdapter
|
37
37
|
end
|
38
38
|
|
39
|
+
it "should find record" do
|
40
|
+
project = MongoidProject.create
|
41
|
+
CanCan::ModelAdapters::MongoidAdapter.find(MongoidProject, project.id).should == project
|
42
|
+
end
|
43
|
+
|
39
44
|
it "should compare properties on mongoid documents with the conditions hash" do
|
40
45
|
model = MongoidProject.new
|
41
46
|
@ability.can :read, MongoidProject, :id => model.id
|
data/spec/spec_helper.rb
CHANGED
@@ -9,11 +9,15 @@ require 'matchers'
|
|
9
9
|
require 'cancan/matchers'
|
10
10
|
|
11
11
|
RSpec.configure do |config|
|
12
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
13
|
+
config.filter_run :focus => true
|
14
|
+
config.run_all_when_everything_filtered = true
|
12
15
|
config.mock_with :rr
|
13
16
|
config.before(:each) do
|
14
17
|
Project.delete_all
|
15
18
|
Category.delete_all
|
16
19
|
end
|
20
|
+
config.extend WithModel
|
17
21
|
end
|
18
22
|
|
19
23
|
class Ability
|
@@ -30,4 +34,12 @@ end
|
|
30
34
|
class Project < SuperModel::Base
|
31
35
|
belongs_to :category
|
32
36
|
attr_accessor :category # why doesn't SuperModel do this automatically?
|
37
|
+
|
38
|
+
def self.respond_to?(method, include_private = false)
|
39
|
+
if method.to_s == "find_by_name!" # hack to simulate ActiveRecord
|
40
|
+
true
|
41
|
+
else
|
42
|
+
super
|
43
|
+
end
|
44
|
+
end
|
33
45
|
end
|
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: 1
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 6
|
9
|
-
-
|
10
|
-
version: 1.6.
|
9
|
+
- 7
|
10
|
+
version: 1.6.7
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Ryan Bates
|
@@ -15,8 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
19
|
-
default_executable:
|
18
|
+
date: 2011-10-04 00:00:00 Z
|
20
19
|
dependencies:
|
21
20
|
- !ruby/object:Gem::Dependency
|
22
21
|
name: rspec
|
@@ -26,12 +25,12 @@ dependencies:
|
|
26
25
|
requirements:
|
27
26
|
- - ~>
|
28
27
|
- !ruby/object:Gem::Version
|
29
|
-
hash:
|
28
|
+
hash: 23
|
30
29
|
segments:
|
31
30
|
- 2
|
32
|
-
-
|
31
|
+
- 6
|
33
32
|
- 0
|
34
|
-
version: 2.
|
33
|
+
version: 2.6.0
|
35
34
|
type: :development
|
36
35
|
version_requirements: *id001
|
37
36
|
- !ruby/object:Gem::Dependency
|
@@ -42,12 +41,12 @@ dependencies:
|
|
42
41
|
requirements:
|
43
42
|
- - ~>
|
44
43
|
- !ruby/object:Gem::Version
|
45
|
-
hash:
|
44
|
+
hash: 21
|
46
45
|
segments:
|
47
46
|
- 3
|
48
47
|
- 0
|
49
|
-
-
|
50
|
-
version: 3.0.
|
48
|
+
- 9
|
49
|
+
version: 3.0.9
|
51
50
|
type: :development
|
52
51
|
version_requirements: *id002
|
53
52
|
- !ruby/object:Gem::Dependency
|
@@ -129,7 +128,6 @@ files:
|
|
129
128
|
- Rakefile
|
130
129
|
- README.rdoc
|
131
130
|
- init.rb
|
132
|
-
has_rdoc: true
|
133
131
|
homepage: http://github.com/ryanb/cancan
|
134
132
|
licenses: []
|
135
133
|
|
@@ -161,7 +159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
161
159
|
requirements: []
|
162
160
|
|
163
161
|
rubyforge_project: cancan
|
164
|
-
rubygems_version: 1.
|
162
|
+
rubygems_version: 1.8.6
|
165
163
|
signing_key:
|
166
164
|
specification_version: 3
|
167
165
|
summary: Simple authorization solution for Rails.
|