cancan 1.6.7 → 1.6.8.rc1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc CHANGED
@@ -1,7 +1,26 @@
1
+ 1.6.8 (unreleased)
2
+
3
+ * improved support for namespaced controllers and models
4
+
5
+ * pass :if and :unless options for load and authorize resource (thanks mauriciozaffari)
6
+
7
+ * Travis CI badge (thanks plentz)
8
+
9
+ * adding Ability#merge for combining multiple abilities (thanks rogercampos)
10
+
11
+ * support for multiple MetaWhere rules (thanks andhapp)
12
+
13
+ * various fixes for DataMapper, Mongoid, and Inherited Resource integration
14
+
15
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.7...master]
16
+
17
+
1
18
  1.6.7 (October 4, 2011)
2
19
 
3
20
  * fixing nested resource problem caused by namespace addition - issue #482
4
21
 
22
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.6...1.6.7]
23
+
5
24
 
6
25
  1.6.6 (September 28, 2011)
7
26
 
@@ -21,6 +40,8 @@
21
40
 
22
41
  * allow :find_by option to be full find method name - issue #335
23
42
 
43
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.5...1.6.6]
44
+
24
45
 
25
46
  1.6.5 (May 18, 2011)
26
47
 
@@ -38,11 +59,15 @@
38
59
 
39
60
  * improve scope merging - issue #328
40
61
 
62
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.4...1.6.5]
63
+
41
64
 
42
65
  1.6.4 (March 29, 2011)
43
66
 
44
67
  * Fixed mongoid 'or' error - see issue #322
45
68
 
69
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.3...1.6.4]
70
+
46
71
 
47
72
  1.6.3 (March 25, 2011)
48
73
 
@@ -50,11 +75,15 @@
50
75
 
51
76
  * Return subject passed to authorize! - see issue #314
52
77
 
78
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.2...1.6.3]
79
+
53
80
 
54
81
  1.6.2 (March 18, 2011)
55
82
 
56
83
  * Fixed instance loading when :singleton option is used - see issue #310
57
84
 
85
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.1...1.6.2]
86
+
58
87
 
59
88
  1.6.1 (March 15, 2011)
60
89
 
@@ -64,6 +93,8 @@
64
93
 
65
94
  * Reverted Inherited Resources "collection" override since it doesn't seem to be working - see issue #305
66
95
 
96
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.0...1.6.1]
97
+
67
98
 
68
99
  1.6.0 (March 11, 2011)
69
100
 
@@ -85,6 +116,8 @@
85
116
 
86
117
  * Raise an exception when trying to make a Ability condition with both a hash of conditions and a block - see issue #269
87
118
 
119
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.5.1...1.6.0]
120
+
88
121
 
89
122
  1.5.1 (January 20, 2011)
90
123
 
@@ -92,6 +125,8 @@
92
125
 
93
126
  * Improving Mongoid support for multiple can and cannot definitions (thanks stellard) - see issue #239
94
127
 
128
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.5.0...1.5.1]
129
+
95
130
 
96
131
  1.5.0 (January 11, 2011)
97
132
 
@@ -113,6 +148,8 @@
113
148
 
114
149
  * Internal: added .rvmrc to auto-switch to 1.8.7 with gemset - see issue #231
115
150
 
151
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.4.1...1.5.0]
152
+
116
153
 
117
154
  1.4.1 (November 12, 2010)
118
155
 
@@ -126,6 +163,8 @@
126
163
 
127
164
  * Fix odd behavior when "cache_classes = false" (thanks mphalliday) - see issue #174
128
165
 
166
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.4.0...1.4.1]
167
+
129
168
 
130
169
  1.4.0 (October 5, 2010)
131
170
 
@@ -165,11 +204,15 @@
165
204
 
166
205
  * No longer calling block in +can+ definition when checking on class - see issue #116
167
206
 
207
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.3.4...1.4.0]
208
+
168
209
 
169
210
  1.3.4 (August 31, 2010)
170
211
 
171
212
  * Don't stop at +cannot+ with hash conditions when checking class (thanks tamoya) - see issue #131
172
213
 
214
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.3.3...1.3.4]
215
+
173
216
 
174
217
  1.3.3 (August 20, 2010)
175
218
 
@@ -177,16 +220,22 @@
177
220
 
178
221
  * Pluralize nested associations for conditions in accessible_by (thanks mlooney) - see issue #123
179
222
 
223
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.3.2...1.3.3]
224
+
180
225
 
181
226
  1.3.2 (August 7, 2010)
182
227
 
183
228
  * Fixing slice error when passing in custom resource name - see issue #112
184
229
 
230
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.3.1...1.3.2]
231
+
185
232
 
186
233
  1.3.1 (August 6, 2010)
187
234
 
188
235
  * Fixing protected sanitize_sql error - see issue #111
189
236
 
237
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.3.0...1.3.1]
238
+
190
239
 
191
240
  1.3.0 (August 6, 2010)
192
241
 
@@ -214,6 +263,8 @@
214
263
 
215
264
  * Supporting deeply nested aliases - see issue #98
216
265
 
266
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.2.0...1.3.0]
267
+
217
268
 
218
269
  1.2.0 (July 16, 2010)
219
270
 
@@ -229,11 +280,15 @@
229
280
 
230
281
  * Adding joins clause to accessible_by when conditions are across associations
231
282
 
283
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.1.1...1.2.0]
284
+
232
285
 
233
286
  1.1.1 (April 17, 2010)
234
287
 
235
288
  * Fixing behavior in Rails 3 by properly initializing ResourceAuthorization
236
289
 
290
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.1...1.1.1]
291
+
237
292
 
238
293
  1.1.0 (April 17, 2010)
239
294
 
@@ -257,6 +312,8 @@
257
312
 
258
313
  * Support additional arguments to can? which get passed to the block - see issue #48
259
314
 
315
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.0.2...1.1]
316
+
260
317
 
261
318
  1.0.2 (Dec 30, 2009)
262
319
 
@@ -266,6 +323,8 @@
266
323
 
267
324
  * Adding custom message argument to unauthorized! method (thanks tjwallace) - see issue #18
268
325
 
326
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.0.1...1.0.2]
327
+
269
328
 
270
329
  1.0.1 (Dec 14, 2009)
271
330
 
@@ -273,6 +332,8 @@
273
332
 
274
333
  * Don't fetch parent of nested resource if *_id parameter is missing so it works with shallow nested routes - see issue #14
275
334
 
335
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.0.0...1.0.1]
336
+
276
337
 
277
338
  1.0.0 (Dec 13, 2009)
278
339
 
@@ -288,6 +349,8 @@
288
349
 
289
350
  * BACKWARDS INCOMPATIBLE: turning load and authorize resource methods into class methods which set up the before filter so they can accept additional arguments.
290
351
 
352
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/0.2.1...1.0.0]
353
+
291
354
 
292
355
  0.2.1 (Nov 26, 2009)
293
356
 
@@ -297,6 +360,8 @@
297
360
 
298
361
  * support custom objects (usually symbols) in can definition - see issue #8
299
362
 
363
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/0.2.0...0.2.1]
364
+
300
365
 
301
366
  0.2.0 (Nov 17, 2009)
302
367
 
@@ -308,6 +373,8 @@
308
373
 
309
374
  * BACKWARDS INCOMPATIBLE: use Ability#initialize instead of 'prepare' to set up abilities - see issue #4
310
375
 
376
+ * {see the full list of changes}[https://github.com/ryanb/cancan/compare/0.1.0...0.2.0]
377
+
311
378
 
312
379
  0.1.0 (Nov 16, 2009)
313
380
 
data/Gemfile CHANGED
@@ -4,7 +4,7 @@ case ENV["MODEL_ADAPTER"]
4
4
  when nil, "active_record"
5
5
  gem "sqlite3"
6
6
  gem "activerecord", '~> 3.0.9', :require => "active_record"
7
- gem "with_model", '~> 0.1.5'
7
+ gem "with_model", "~> 0.2.5"
8
8
  gem "meta_where"
9
9
  when "data_mapper"
10
10
  gem "dm-core", "~> 1.0.2"
data/README.rdoc CHANGED
@@ -1,4 +1,4 @@
1
- = CanCan
1
+ = CanCan {<img src="https://secure.travis-ci.org/ryanb/cancan.png" />}[http://travis-ci.org/ryanb/cancan]
2
2
 
3
3
  Wiki[https://github.com/ryanb/cancan/wiki] | RDocs[http://rdoc.info/projects/ryanb/cancan] | Screencast[http://railscasts.com/episodes/192-authorization-with-cancan]
4
4
 
@@ -31,6 +31,15 @@ User permissions are defined in an +Ability+ class. CanCan 1.5 includes a Rails
31
31
 
32
32
  rails g cancan:ability
33
33
 
34
+ In Rails 2.3, just add a new class in `app/models/ability.rb` with the folowing contents:
35
+
36
+ class Ability
37
+ include CanCan::Ability
38
+
39
+ def initialize(user)
40
+ end
41
+ end
42
+
34
43
  See {Defining Abilities}[https://github.com/ryanb/cancan/wiki/defining-abilities] for details.
35
44
 
36
45
 
@@ -228,6 +228,13 @@ module CanCan
228
228
  relevant_rules(action, subject).any?(&:only_raw_sql?)
229
229
  end
230
230
 
231
+ def merge(ability)
232
+ ability.send(:rules).each do |rule|
233
+ rules << rule.dup
234
+ end
235
+ self
236
+ end
237
+
231
238
  private
232
239
 
233
240
  def unauthorized_message_keys(action, subject)
@@ -94,7 +94,7 @@ module CanCan
94
94
  # [:+find_by+]
95
95
  # Find using a different attribute other than id. For example.
96
96
  #
97
- # load_resource :find_by => :permalink # will use find_by_permlink!(params[:id])
97
+ # load_resource :find_by => :permalink # will use find_by_permalink!(params[:id])
98
98
  #
99
99
  # [:+collection+]
100
100
  # Specify which actions are resource collection actions in addition to :+index+. This
@@ -151,6 +151,9 @@ module CanCan
151
151
  # [:+except+]
152
152
  # Does not apply before filter to given actions.
153
153
  #
154
+ # [:+singleton+]
155
+ # Pass +true+ if this is a singleton resource through a +has_one+ association.
156
+ #
154
157
  # [:+parent+]
155
158
  # True or false depending on if the resource is considered a parent resource. This defaults to +true+ if a resource
156
159
  # name is given which does not match the controller.
@@ -382,7 +385,7 @@ module CanCan
382
385
  end
383
386
  end
384
387
 
385
- if defined? ActionController
388
+ if defined? ActionController::Base
386
389
  ActionController::Base.class_eval do
387
390
  include CanCan::ControllerAdditions
388
391
  end
@@ -6,8 +6,8 @@ module CanCan
6
6
  options = args.extract_options!
7
7
  resource_name = args.first
8
8
  before_filter_method = options.delete(:prepend) ? :prepend_before_filter : :before_filter
9
- controller_class.send(before_filter_method, options.slice(:only, :except)) do |controller|
10
- controller.class.cancan_resource_class.new(controller, resource_name, options.except(:only, :except)).send(method)
9
+ controller_class.send(before_filter_method, options.slice(:only, :except, :if, :unless)) do |controller|
10
+ controller.class.cancan_resource_class.new(controller, resource_name, options.except(:only, :except, :if, :unless)).send(method)
11
11
  end
12
12
  end
13
13
 
@@ -82,7 +82,11 @@ module CanCan
82
82
  end
83
83
 
84
84
  def build_resource
85
- resource = resource_base.new(@params[name] || {})
85
+ resource = resource_base.new(resource_params || {})
86
+ assign_attributes(resource)
87
+ end
88
+
89
+ def assign_attributes(resource)
86
90
  resource.send("#{parent_name}=", parent_resource) if @options[:singleton] && parent_resource
87
91
  initial_attributes.each do |attr_name, value|
88
92
  resource.send("#{attr_name}=", value)
@@ -92,7 +96,7 @@ module CanCan
92
96
 
93
97
  def initial_attributes
94
98
  current_ability.attributes_for(@params[:action].to_sym, resource_class).delete_if do |key, value|
95
- @params[name] && @params[name].include?(key)
99
+ resource_params && resource_params.include?(key)
96
100
  end
97
101
  end
98
102
 
@@ -207,8 +211,20 @@ module CanCan
207
211
  @name || name_from_controller
208
212
  end
209
213
 
214
+ def resource_params
215
+ if @options[:class]
216
+ @params[@options[:class].to_s.underscore.gsub('/', '_')]
217
+ else
218
+ @params[namespaced_name.to_s.underscore.gsub("/", "_")]
219
+ end
220
+ end
221
+
222
+ def namespace
223
+ @params[:controller].split("::")[0..-2]
224
+ end
225
+
210
226
  def namespaced_name
211
- @name || @params[:controller].sub("Controller", "").singularize.camelize.constantize
227
+ [namespace, name.camelize].join('::').singularize.camelize.constantize
212
228
  rescue NameError
213
229
  name
214
230
  end
@@ -6,7 +6,8 @@ module CanCan
6
6
  @controller.send :association_chain
7
7
  @controller.instance_variable_get("@#{instance_name}")
8
8
  elsif new_actions.include? @params[:action].to_sym
9
- @controller.send :build_resource
9
+ resource = @controller.send :build_resource
10
+ assign_attributes(resource)
10
11
  else
11
12
  @controller.send :resource
12
13
  end
@@ -89,7 +89,12 @@ module CanCan
89
89
  if override_scope
90
90
  @model_class.scoped.merge(override_scope)
91
91
  elsif @model_class.respond_to?(:where) && @model_class.respond_to?(:joins)
92
- @model_class.where(conditions).joins(joins)
92
+ mergeable_conditions = @rules.select {|rule| rule.unmergeable? }.blank?
93
+ if mergeable_conditions
94
+ @model_class.where(conditions).joins(joins)
95
+ else
96
+ @model_class.where(*(@rules.map(&:conditions))).joins(joins)
97
+ end
93
98
  else
94
99
  @model_class.scoped(:conditions => conditions, :joins => joins)
95
100
  end
@@ -30,8 +30,9 @@ module CanCan
30
30
  else
31
31
  # we only need to process can rules if
32
32
  # there are no rules with empty conditions
33
- rules = @rules.reject { |rule| rule.conditions.empty? }
33
+ rules = @rules.reject { |rule| rule.conditions.empty? && rule.base_behavior }
34
34
  process_can_rules = @rules.count == rules.count
35
+
35
36
  rules.inject(@model_class.all) do |records, rule|
36
37
  if process_can_rules && rule.base_behavior
37
38
  records.or rule.conditions
data/lib/cancan/rule.rb CHANGED
@@ -54,6 +54,10 @@ module CanCan
54
54
  @conditions == {} || @conditions.nil?
55
55
  end
56
56
 
57
+ def unmergeable?
58
+ @conditions.respond_to?(:keys) && (! @conditions.keys.first.kind_of? Symbol)
59
+ end
60
+
57
61
  def associations_hash(conditions = @conditions)
58
62
  hash = {}
59
63
  conditions.map do |name, value|
@@ -111,7 +115,7 @@ module CanCan
111
115
  else
112
116
  !attribute.nil? && matches_conditions_hash?(attribute, value)
113
117
  end
114
- elsif value.kind_of?(Array) || value.kind_of?(Range)
118
+ elsif value.kind_of?(Enumerable)
115
119
  value.include? attribute
116
120
  else
117
121
  attribute == value
@@ -123,7 +127,7 @@ module CanCan
123
127
  end
124
128
 
125
129
  def nested_subject_matches_conditions?(subject_hash)
126
- parent, child = subject_hash.shift
130
+ parent, child = subject_hash.first
127
131
  matches_conditions_hash?(parent, @conditions[parent.class.name.downcase.to_sym] || {})
128
132
  end
129
133
 
@@ -136,7 +140,7 @@ module CanCan
136
140
  end
137
141
 
138
142
  def model_adapter(subject)
139
- ModelAdapters::AbstractAdapter.adapter_class(subject_class?(subject) ? subject : subject.class)
143
+ CanCan::ModelAdapters::AbstractAdapter.adapter_class(subject_class?(subject) ? subject : subject.class)
140
144
  end
141
145
  end
142
146
  end
@@ -249,7 +249,15 @@ describe CanCan::Ability do
249
249
  @ability.can?(:read, 1..5).should be_true
250
250
  @ability.can?(:read, 4..6).should be_false
251
251
  end
252
-
252
+
253
+ it "should accept a set as a condition value" do
254
+ mock(object_with_foo_2 = Object.new).foo { 2 }
255
+ mock(object_with_foo_3 = Object.new).foo { 3 }
256
+ @ability.can :read, Object, :foo => [1, 2, 5].to_set
257
+ @ability.can?(:read, object_with_foo_2).should be_true
258
+ @ability.can?(:read, object_with_foo_3).should be_false
259
+ end
260
+
253
261
  it "should not match subjects return nil for methods that must match nested a nested conditions hash" do
254
262
  mock(object_with_foo = Object.new).foo { :bar }
255
263
  @ability.can :read, Array, :first => { :foo => :bar }
@@ -297,7 +305,15 @@ describe CanCan::Ability do
297
305
  @ability.can?(:read, "foobar" => Range).should be_false
298
306
  @ability.can?(:read, 123 => Range).should be_true
299
307
  end
300
-
308
+
309
+ it "passing a hash of subjects with multiple definitions should check permissions correctly" do
310
+ @ability.can :read, Range, :string => {:length => 4}
311
+ @ability.can [:create, :read], Range, :string => {:upcase => 'FOO'}
312
+ @ability.can?(:read, "foo" => Range).should be_true
313
+ @ability.can?(:read, "foobar" => Range).should be_false
314
+ @ability.can?(:read, 1234 => Range).should be_true
315
+ end
316
+
301
317
  it "should allow to check ability on Hash-like object" do
302
318
  class Container < Hash; end
303
319
  @ability.can :read, Container
@@ -416,4 +432,17 @@ describe CanCan::Ability do
416
432
  @ability.unauthorized_message(:edit, 1..3).should == "edit range"
417
433
  end
418
434
  end
435
+
436
+ describe "#merge" do
437
+ it "should add the rules from the given ability" do
438
+ @ability.can :use, :tools
439
+ another_ability = Object.new
440
+ another_ability.extend(CanCan::Ability)
441
+ another_ability.can :use, :search
442
+
443
+ @ability.merge(another_ability)
444
+ @ability.can?(:use, :search).should be_true
445
+ @ability.send(:rules).size.should == 2
446
+ end
447
+ end
419
448
  end
@@ -49,14 +49,14 @@ describe CanCan::ControllerAdditions do
49
49
 
50
50
  it "authorize_resource should setup a before filter which passes call to ControllerResource" do
51
51
  stub(CanCan::ControllerResource).new(@controller, nil, :foo => :bar).mock!.authorize_resource
52
- mock(@controller_class).before_filter(:except => :show) { |options, block| block.call(@controller) }
53
- @controller_class.authorize_resource :foo => :bar, :except => :show
52
+ mock(@controller_class).before_filter(:except => :show, :if => true) { |options, block| block.call(@controller) }
53
+ @controller_class.authorize_resource :foo => :bar, :except => :show, :if => true
54
54
  end
55
55
 
56
56
  it "load_resource should setup a before filter which passes call to ControllerResource" do
57
57
  stub(CanCan::ControllerResource).new(@controller, nil, :foo => :bar).mock!.load_resource
58
- mock(@controller_class).before_filter(:only => [:show, :index]) { |options, block| block.call(@controller) }
59
- @controller_class.load_resource :foo => :bar, :only => [:show, :index]
58
+ mock(@controller_class).before_filter(:only => [:show, :index], :unless => false) { |options, block| block.call(@controller) }
59
+ @controller_class.load_resource :foo => :bar, :only => [:show, :index], :unless => false
60
60
  end
61
61
 
62
62
  it "skip_authorization_check should set up a before filter which sets @_authorized to true" do
@@ -47,6 +47,18 @@ describe CanCan::ControllerResource do
47
47
  @controller.instance_variable_get(:@project).should == project
48
48
  end
49
49
 
50
+ # Rails includes namespace in params, see issue #349
51
+ it "should create through the namespaced params" do
52
+ module MyEngine
53
+ class Project < ::Project; end
54
+ end
55
+
56
+ @params.merge!(:controller => "MyEngine::ProjectsController", :action => "create", :my_engine_project => {:name => "foobar"})
57
+ resource = CanCan::ControllerResource.new(@controller)
58
+ resource.load_resource
59
+ @controller.instance_variable_get(:@project).name.should == "foobar"
60
+ end
61
+
50
62
  it "should properly load resource for namespaced controller when using '::' for namespace" do
51
63
  project = Project.create!
52
64
  @params.merge!(:controller => "Admin::ProjectsController", :action => "show", :id => project.id)
@@ -62,6 +74,14 @@ describe CanCan::ControllerResource do
62
74
  @controller.instance_variable_get(:@project).name.should == "foobar"
63
75
  end
64
76
 
77
+ it "should build a new resource for namespaced model with hash if params[:id] is not specified" do
78
+ project = Sub::Project.create!
79
+ @params.merge!(:action => "create", 'sub_project' => {:name => "foobar"})
80
+ resource = CanCan::ControllerResource.new(@controller, :class => ::Sub::Project)
81
+ resource.load_resource
82
+ @controller.instance_variable_get(:@project).name.should == "foobar"
83
+ end
84
+
65
85
  it "should build a new resource with attributes from current ability" do
66
86
  @params.merge!(:action => "new")
67
87
  @ability.can(:create, Project, :name => "from conditions")
@@ -195,6 +215,14 @@ describe CanCan::ControllerResource do
195
215
  resource.should_not be_parent
196
216
  end
197
217
 
218
+ it "should have the specified resource_class if 'name' is passed to load_resource" do
219
+ class Section
220
+ end
221
+
222
+ resource = CanCan::ControllerResource.new(@controller, :section)
223
+ resource.send(:resource_class).should == Section
224
+ end
225
+
198
226
  it "should load parent resource through proper id parameter" do
199
227
  project = Project.create!
200
228
  @params.merge!(:controller => "categories", :action => "index", :project_id => project.id)
@@ -324,6 +352,14 @@ describe CanCan::ControllerResource do
324
352
  @controller.instance_variable_get(:@project).should == project
325
353
  end
326
354
 
355
+ it "should load the model using a custom namespaced class" do
356
+ project = Sub::Project.create!
357
+ @params.merge!(:action => "show", :id => project.id)
358
+ resource = CanCan::ControllerResource.new(@controller, :class => ::Sub::Project)
359
+ resource.load_resource
360
+ @controller.instance_variable_get(:@project).should == project
361
+ end
362
+
327
363
  it "should authorize based on resource name if class is false" do
328
364
  @params.merge!(:action => "show", :id => 123)
329
365
  stub(@controller).authorize!(:show, :project) { raise CanCan::AccessDenied }
@@ -339,7 +375,7 @@ describe CanCan::ControllerResource do
339
375
  lambda { resource.load_and_authorize_resource }.should raise_error(CanCan::AccessDenied)
340
376
  @controller.instance_variable_get(:@custom_project).should == project
341
377
  end
342
-
378
+
343
379
  it "should load resource using custom ID param" do
344
380
  project = Project.create!
345
381
  @params.merge!(:action => "show", :the_project => project.id)
@@ -347,7 +383,7 @@ describe CanCan::ControllerResource do
347
383
  resource.load_resource
348
384
  @controller.instance_variable_get(:@project).should == project
349
385
  end
350
-
386
+
351
387
  it "should load resource using custom find_by attribute" do
352
388
  project = Project.create!(:name => "foo")
353
389
  @params.merge!(:action => "show", :id => "foo")
@@ -32,23 +32,23 @@ describe CanCan::AccessDenied do
32
32
  @exception.message.should == "Access denied!"
33
33
  end
34
34
  end
35
-
35
+
36
36
  describe "i18n in the default message" do
37
37
  after(:each) do
38
38
  I18n.backend = nil
39
39
  end
40
-
40
+
41
41
  it "uses i18n for the default message" do
42
42
  I18n.backend.store_translations :en, :unauthorized => {:default => "This is a different message"}
43
43
  @exception = CanCan::AccessDenied.new
44
44
  @exception.message.should == "This is a different message"
45
45
  end
46
-
46
+
47
47
  it "defaults to a nice message" do
48
48
  @exception = CanCan::AccessDenied.new
49
49
  @exception.message.should == "You are not authorized to access this page."
50
50
  end
51
-
51
+
52
52
  it "does not use translation if a message is given" do
53
53
  @exception = CanCan::AccessDenied.new("Hey! You're not welcome here")
54
54
  @exception.message.should == "Hey! You're not welcome here"
@@ -39,4 +39,22 @@ describe CanCan::InheritedResource do
39
39
  CanCan::InheritedResource.new(@controller).load_resource
40
40
  @controller.instance_variable_get(:@projects).should == :projects
41
41
  end
42
+
43
+ it "should build a new resource with attributes from current ability" do
44
+ @params[:action] = "new"
45
+ @ability.can(:create, Project, :name => "from conditions")
46
+ stub(@controller).build_resource { Struct.new(:name).new }
47
+ resource = CanCan::InheritedResource.new(@controller)
48
+ resource.load_resource
49
+ @controller.instance_variable_get(:@project).name.should == "from conditions"
50
+ end
51
+
52
+ it "should override initial attributes with params" do
53
+ @params.merge!(:action => "new", :project => {:name => "from params"})
54
+ @ability.can(:create, Project, :name => "from conditions")
55
+ stub(@controller).build_resource { Struct.new(:name).new }
56
+ resource = CanCan::ControllerResource.new(@controller)
57
+ resource.load_resource
58
+ @controller.instance_variable_get(:@project).name.should == "from params"
59
+ end
42
60
  end
@@ -133,7 +133,7 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
133
133
  article1 = Article.create!(:secret => true, :category => category1)
134
134
  article2 = Article.create!(:secret => true, :category => category2)
135
135
  category1.articles.accessible_by(@ability).should == [article1]
136
- end
136
+ end
137
137
 
138
138
  it "should raise an exception when trying to merge scope with other conditions" do
139
139
  @ability.can :read, Article, :published => true
@@ -236,6 +236,16 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
236
236
  @ability.should_not be_able_to(:read, article2)
237
237
  end
238
238
 
239
+ it "should merge MetaWhere and non-MetaWhere conditions" do
240
+ @ability.can :read, Article, :priority.lt => 2
241
+ @ability.can :read, Article, :priority => 1
242
+ article1 = Article.create!(:priority => 1)
243
+ article2 = Article.create!(:priority => 3)
244
+ Article.accessible_by(@ability).should == [article1]
245
+ @ability.should be_able_to(:read, article1)
246
+ @ability.should_not be_able_to(:read, article2)
247
+ end
248
+
239
249
  it "should match any MetaWhere condition" do
240
250
  adapter = CanCan::ModelAdapters::ActiveRecordAdapter
241
251
  article1 = Article.new(:priority => 1, :name => "Hello World")
@@ -73,6 +73,17 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
73
73
  MongoidProject.accessible_by(@ability, :read).entries.should == [sir]
74
74
  end
75
75
 
76
+ it "should return the correct records when a mix of can and cannot rules in defined ability" do
77
+ @ability.can :manage, MongoidProject, :title => 'Sir'
78
+ @ability.cannot :destroy, MongoidProject
79
+
80
+ sir = MongoidProject.create(:title => 'Sir')
81
+ lord = MongoidProject.create(:title => 'Lord')
82
+ dude = MongoidProject.create(:title => 'Dude')
83
+
84
+ MongoidProject.accessible_by(@ability, :destroy).entries.should == [sir]
85
+ end
86
+
76
87
  it "should be able to mix empty conditions and hashes" do
77
88
  @ability.can :read, MongoidProject
78
89
  @ability.can :read, MongoidProject, :title => 'Sir'
@@ -185,7 +196,7 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
185
196
  @ability.can :read, MongoidProject, :foo => {:bar => 1}
186
197
  MongoidProject.accessible_by(@ability, :read).entries.first.should == obj
187
198
  end
188
-
199
+
189
200
  it "should exclude from the result if set to cannot" do
190
201
  obj = MongoidProject.create(:bar => 1)
191
202
  obj2 = MongoidProject.create(:bar => 2)
@@ -202,7 +213,7 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
202
213
  @ability.can :read, MongoidProject, :bar => 2
203
214
  MongoidProject.accessible_by(@ability, :read).entries.should =~ [obj, obj2]
204
215
  end
205
-
216
+
206
217
  it "should not allow to fetch records when ability with just block present" do
207
218
  @ability.can :read, MongoidProject do
208
219
  false
@@ -1,4 +1,5 @@
1
1
  require "spec_helper"
2
+ require "ostruct" # for OpenStruct below
2
3
 
3
4
  # Most of Rule functionality is tested in Ability specs
4
5
  describe CanCan::Rule do
@@ -36,4 +37,11 @@ describe CanCan::Rule do
36
37
  rule = CanCan::Rule.new(true, :read, Integer, nil, nil)
37
38
  rule.associations_hash.should == {}
38
39
  end
40
+
41
+ it "should not be mergeable if conditions are not simple hashes" do
42
+ meta_where = OpenStruct.new(:name => 'metawhere', :column => 'test')
43
+ @conditions[meta_where] = :bar
44
+
45
+ @rule.should be_unmergeable
46
+ end
39
47
  end
data/spec/spec_helper.rb CHANGED
@@ -17,7 +17,7 @@ RSpec.configure do |config|
17
17
  Project.delete_all
18
18
  Category.delete_all
19
19
  end
20
- config.extend WithModel
20
+ config.extend WithModel if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
21
21
  end
22
22
 
23
23
  class Ability
@@ -31,6 +31,21 @@ class Category < SuperModel::Base
31
31
  has_many :projects
32
32
  end
33
33
 
34
+ module Sub
35
+ class Project < SuperModel::Base
36
+ belongs_to :category
37
+ attr_accessor :category # why doesn't SuperModel do this automatically?
38
+
39
+ def self.respond_to?(method, include_private = false)
40
+ if method.to_s == "find_by_name!" # hack to simulate ActiveRecord
41
+ true
42
+ else
43
+ super
44
+ end
45
+ end
46
+ end
47
+ end
48
+
34
49
  class Project < SuperModel::Base
35
50
  belongs_to :category
36
51
  attr_accessor :category # why doesn't SuperModel do this automatically?
metadata CHANGED
@@ -1,13 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cancan
3
3
  version: !ruby/object:Gem::Version
4
- hash: 1
5
- prerelease:
4
+ hash: -2317773892
5
+ prerelease: 6
6
6
  segments:
7
7
  - 1
8
8
  - 6
9
- - 7
10
- version: 1.6.7
9
+ - 8
10
+ - rc
11
+ - 1
12
+ version: 1.6.8.rc1
11
13
  platform: ruby
12
14
  authors:
13
15
  - Ryan Bates
@@ -15,7 +17,8 @@ autorequire:
15
17
  bindir: bin
16
18
  cert_chain: []
17
19
 
18
- date: 2011-10-04 00:00:00 Z
20
+ date: 2012-06-19 00:00:00 -07:00
21
+ default_executable:
19
22
  dependencies:
20
23
  - !ruby/object:Gem::Dependency
21
24
  name: rspec
@@ -128,6 +131,7 @@ files:
128
131
  - Rakefile
129
132
  - README.rdoc
130
133
  - init.rb
134
+ has_rdoc: true
131
135
  homepage: http://github.com/ryanb/cancan
132
136
  licenses: []
133
137
 
@@ -159,7 +163,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
159
163
  requirements: []
160
164
 
161
165
  rubyforge_project: cancan
162
- rubygems_version: 1.8.6
166
+ rubygems_version: 1.6.2
163
167
  signing_key:
164
168
  specification_version: 3
165
169
  summary: Simple authorization solution for Rails.