cancancan 1.11.0 → 2.3.0

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.
Files changed (70) hide show
  1. checksums.yaml +5 -5
  2. data/cancancan.gemspec +15 -19
  3. data/lib/cancan/ability/actions.rb +91 -0
  4. data/lib/cancan/ability/rules.rb +85 -0
  5. data/lib/cancan/ability.rb +74 -136
  6. data/lib/cancan/conditions_matcher.rb +93 -0
  7. data/lib/cancan/controller_additions.rb +34 -40
  8. data/lib/cancan/controller_resource.rb +47 -212
  9. data/lib/cancan/controller_resource_builder.rb +24 -0
  10. data/lib/cancan/controller_resource_finder.rb +40 -0
  11. data/lib/cancan/controller_resource_loader.rb +116 -0
  12. data/lib/cancan/controller_resource_name_finder.rb +21 -0
  13. data/lib/cancan/controller_resource_sanitizer.rb +30 -0
  14. data/lib/cancan/exceptions.rb +7 -3
  15. data/lib/cancan/matchers.rb +12 -3
  16. data/lib/cancan/model_adapters/abstract_adapter.rb +8 -8
  17. data/lib/cancan/model_adapters/active_record_4_adapter.rb +33 -10
  18. data/lib/cancan/model_adapters/active_record_5_adapter.rb +70 -0
  19. data/lib/cancan/model_adapters/active_record_adapter.rb +41 -81
  20. data/lib/cancan/model_adapters/can_can/model_adapters/active_record_adapter/joins.rb +39 -0
  21. data/lib/cancan/model_adapters/conditions_extractor.rb +75 -0
  22. data/lib/cancan/model_additions.rb +0 -1
  23. data/lib/cancan/rule.rb +36 -92
  24. data/lib/cancan/rules_compressor.rb +20 -0
  25. data/lib/cancan/version.rb +1 -1
  26. data/lib/cancan.rb +5 -12
  27. data/lib/generators/cancan/ability/ability_generator.rb +1 -1
  28. metadata +54 -65
  29. data/.gitignore +0 -15
  30. data/.rspec +0 -1
  31. data/.travis.yml +0 -55
  32. data/Appraisals +0 -136
  33. data/CHANGELOG.rdoc +0 -503
  34. data/CONTRIBUTING.md +0 -23
  35. data/Gemfile +0 -3
  36. data/LICENSE +0 -22
  37. data/README.md +0 -188
  38. data/Rakefile +0 -9
  39. data/gemfiles/activerecord_3.0.gemfile +0 -18
  40. data/gemfiles/activerecord_3.1.gemfile +0 -20
  41. data/gemfiles/activerecord_3.2.gemfile +0 -20
  42. data/gemfiles/activerecord_4.0.gemfile +0 -17
  43. data/gemfiles/activerecord_4.1.gemfile +0 -17
  44. data/gemfiles/activerecord_4.2.gemfile +0 -18
  45. data/gemfiles/datamapper_1.x.gemfile +0 -14
  46. data/gemfiles/mongoid_2.x.gemfile +0 -20
  47. data/gemfiles/sequel_3.x.gemfile +0 -20
  48. data/lib/cancan/inherited_resource.rb +0 -20
  49. data/lib/cancan/model_adapters/active_record_3_adapter.rb +0 -47
  50. data/lib/cancan/model_adapters/data_mapper_adapter.rb +0 -34
  51. data/lib/cancan/model_adapters/mongoid_adapter.rb +0 -54
  52. data/lib/cancan/model_adapters/sequel_adapter.rb +0 -87
  53. data/spec/README.rdoc +0 -27
  54. data/spec/cancan/ability_spec.rb +0 -487
  55. data/spec/cancan/controller_additions_spec.rb +0 -141
  56. data/spec/cancan/controller_resource_spec.rb +0 -632
  57. data/spec/cancan/exceptions_spec.rb +0 -58
  58. data/spec/cancan/inherited_resource_spec.rb +0 -71
  59. data/spec/cancan/matchers_spec.rb +0 -29
  60. data/spec/cancan/model_adapters/active_record_4_adapter_spec.rb +0 -85
  61. data/spec/cancan/model_adapters/active_record_adapter_spec.rb +0 -446
  62. data/spec/cancan/model_adapters/data_mapper_adapter_spec.rb +0 -119
  63. data/spec/cancan/model_adapters/default_adapter_spec.rb +0 -7
  64. data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +0 -227
  65. data/spec/cancan/model_adapters/sequel_adapter_spec.rb +0 -132
  66. data/spec/cancan/rule_spec.rb +0 -52
  67. data/spec/matchers.rb +0 -13
  68. data/spec/spec.opts +0 -2
  69. data/spec/spec_helper.rb +0 -28
  70. data/spec/support/ability.rb +0 -7
@@ -1,5 +1,4 @@
1
1
  module CanCan
2
-
3
2
  # This module is automatically included into all controllers.
4
3
  # It also makes the "can?" and "cannot?" methods available to all views.
5
4
  module ControllerAdditions
@@ -12,7 +11,7 @@ module CanCan
12
11
  # end
13
12
  #
14
13
  def load_and_authorize_resource(*args)
15
- cancan_resource_class.add_before_filter(self, :load_and_authorize_resource, *args)
14
+ cancan_resource_class.add_before_action(self, :load_and_authorize_resource, *args)
16
15
  end
17
16
 
18
17
  # Sets up a before filter which loads the model resource into an instance variable.
@@ -32,16 +31,16 @@ module CanCan
32
31
  # end
33
32
  #
34
33
  # A resource is not loaded if the instance variable is already set. This makes it easy to override
35
- # the behavior through a before_filter on certain actions.
34
+ # the behavior through a before_action on certain actions.
36
35
  #
37
36
  # class BooksController < ApplicationController
38
- # before_filter :find_book_by_permalink, :only => :show
37
+ # before_action :find_book_by_permalink, :only => :show
39
38
  # load_resource
40
39
  #
41
40
  # private
42
41
  #
43
42
  # def find_book_by_permalink
44
- # @book = Book.find_by_permalink!(params[:id)
43
+ # @book = Book.find_by_permalink!(params[:id])
45
44
  # end
46
45
  # end
47
46
  #
@@ -72,8 +71,8 @@ module CanCan
72
71
  # Load this resource through another one. This should match the name of the parent instance variable or method.
73
72
  #
74
73
  # [:+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.
74
+ # The name of the association to fetch the child records through the parent resource.
75
+ # This is normally not needed because it defaults to the pluralized resource name.
77
76
  #
78
77
  # [:+shallow+]
79
78
  # Pass +true+ to allow this resource to be loaded directly when parent is +nil+. Defaults to +false+.
@@ -82,8 +81,8 @@ module CanCan
82
81
  # Pass +true+ if this is a singleton resource through a +has_one+ association.
83
82
  #
84
83
  # [:+parent+]
85
- # True or false depending on if the resource is considered a parent resource. This defaults to +true+ if a resource
86
- # name is given which does not match the controller.
84
+ # True or false depending on if the resource is considered a parent resource.
85
+ # This defaults to +true+ if a resource name is given which does not match the controller.
87
86
  #
88
87
  # [:+class+]
89
88
  # The class to use for the model (string or constant).
@@ -115,10 +114,10 @@ module CanCan
115
114
  # load_resource :new => :build
116
115
  #
117
116
  # [:+prepend+]
118
- # Passing +true+ will use prepend_before_filter instead of a normal before_filter.
117
+ # Passing +true+ will use prepend_before_action instead of a normal before_action.
119
118
  #
120
119
  def load_resource(*args)
121
- cancan_resource_class.add_before_filter(self, :load_resource, *args)
120
+ cancan_resource_class.add_before_action(self, :load_resource, *args)
122
121
  end
123
122
 
124
123
  # Sets up a before filter which authorizes the resource using the instance variable.
@@ -160,8 +159,8 @@ module CanCan
160
159
  # Pass +true+ if this is a singleton resource through a +has_one+ association.
161
160
  #
162
161
  # [:+parent+]
163
- # True or false depending on if the resource is considered a parent resource. This defaults to +true+ if a resource
164
- # name is given which does not match the controller.
162
+ # True or false depending on if the resource is considered a parent resource.
163
+ # This defaults to +true+ if a resource name is given which does not match the controller.
165
164
  #
166
165
  # [:+class+]
167
166
  # The class to use for the model (string or constant). This passed in when the instance variable is not set.
@@ -174,10 +173,10 @@ module CanCan
174
173
  # Authorize conditions on this parent resource when instance isn't available.
175
174
  #
176
175
  # [:+prepend+]
177
- # Passing +true+ will use prepend_before_filter instead of a normal before_filter.
176
+ # Passing +true+ will use prepend_before_action instead of a normal before_action.
178
177
  #
179
178
  def authorize_resource(*args)
180
- cancan_resource_class.add_before_filter(self, :authorize_resource, *args)
179
+ cancan_resource_class.add_before_action(self, :authorize_resource, *args)
181
180
  end
182
181
 
183
182
  # Skip both the loading and authorization behavior of CanCan for this given controller. This is primarily
@@ -227,7 +226,8 @@ module CanCan
227
226
  end
228
227
 
229
228
  # Add this to a controller to ensure it performs authorization through +authorized+! or +authorize_resource+ call.
230
- # If neither of these authorization methods are called, a CanCan::AuthorizationNotPerformed exception will be raised.
229
+ # If neither of these authorization methods are called,
230
+ # a CanCan::AuthorizationNotPerformed exception will be raised.
231
231
  # This is normally added to the ApplicationController to ensure all controller actions do authorization.
232
232
  #
233
233
  # class ApplicationController < ActionController::Base
@@ -244,22 +244,28 @@ module CanCan
244
244
  # Does not apply to given actions.
245
245
  #
246
246
  # [:+if+]
247
- # Supply the name of a controller method to be called. The authorization check only takes place if this returns true.
247
+ # Supply the name of a controller method to be called.
248
+ # The authorization check only takes place if this returns true.
248
249
  #
249
250
  # check_authorization :if => :admin_controller?
250
251
  #
251
252
  # [:+unless+]
252
- # Supply the name of a controller method to be called. The authorization check only takes place if this returns false.
253
+ # Supply the name of a controller method to be called.
254
+ # The authorization check only takes place if this returns false.
253
255
  #
254
256
  # check_authorization :unless => :devise_controller?
255
257
  #
256
258
  def check_authorization(options = {})
257
- self.after_filter(options.slice(:only, :except)) do |controller|
259
+ block = proc do |controller|
258
260
  next if controller.instance_variable_defined?(:@_authorized)
259
261
  next if options[:if] && !controller.send(options[:if])
260
262
  next if options[:unless] && controller.send(options[:unless])
261
- raise AuthorizationNotPerformed, "This action failed the check_authorization because it does not authorize_resource. Add skip_authorization_check to bypass this check."
263
+ raise AuthorizationNotPerformed,
264
+ 'This action failed the check_authorization because it does not authorize_resource. '\
265
+ 'Add skip_authorization_check to bypass this check.'
262
266
  end
267
+
268
+ send(:after_action, options.slice(:only, :except), &block)
263
269
  end
264
270
 
265
271
  # Call this in the class of a controller to skip the check_authorization behavior on the actions.
@@ -268,33 +274,25 @@ module CanCan
268
274
  # skip_authorization_check :only => :index
269
275
  # end
270
276
  #
271
- # Any arguments are passed to the +before_filter+ it triggers.
277
+ # Any arguments are passed to the +before_action+ it triggers.
272
278
  def skip_authorization_check(*args)
273
- self.before_filter(*args) do |controller|
274
- controller.instance_variable_set(:@_authorized, true)
275
- end
276
- end
277
-
278
- def skip_authorization(*args)
279
- raise ImplementationRemoved, "The CanCan skip_authorization method has been renamed to skip_authorization_check. Please update your code."
279
+ block = proc { |controller| controller.instance_variable_set(:@_authorized, true) }
280
+ send(:before_action, *args, &block)
280
281
  end
281
282
 
282
283
  def cancan_resource_class
283
- if ancestors.map(&:to_s).include? "InheritedResources::Actions"
284
- InheritedResource
285
- else
286
- ControllerResource
287
- end
284
+ ControllerResource
288
285
  end
289
286
 
290
287
  def cancan_skipper
291
- @_cancan_skipper ||= {:authorize => {}, :load => {}}
288
+ self._cancan_skipper ||= { authorize: {}, load: {} }
292
289
  end
293
290
  end
294
291
 
295
292
  def self.included(base)
296
293
  base.extend ClassMethods
297
294
  base.helper_method :can?, :cannot?, :current_ability if base.respond_to? :helper_method
295
+ base.class_attribute :_cancan_skipper
298
296
  end
299
297
 
300
298
  # Raises a CanCan::AccessDenied exception if the current_ability cannot
@@ -338,10 +336,6 @@ module CanCan
338
336
  current_ability.authorize!(*args)
339
337
  end
340
338
 
341
- def unauthorized!(message = nil)
342
- raise ImplementationRemoved, "The unauthorized! method has been removed from CanCan, use authorize! instead."
343
- end
344
-
345
339
  # Creates and returns the current user's ability and caches it. If you
346
340
  # want to override how the Ability is defined then this is the place.
347
341
  # Just define the method in the controller to change behavior.
@@ -390,8 +384,8 @@ module CanCan
390
384
  end
391
385
  end
392
386
 
393
- if defined? ActionController::Base
394
- ActionController::Base.class_eval do
387
+ if defined? ActiveSupport
388
+ ActiveSupport.on_load(:action_controller) do
395
389
  include CanCan::ControllerAdditions
396
390
  end
397
391
  end
@@ -1,24 +1,30 @@
1
+ require_relative 'controller_resource_loader.rb'
1
2
  module CanCan
2
- # Handle the load and authorization controller logic so we don't clutter up all controllers with non-interface methods.
3
+ # Handle the load and authorization controller logic
4
+ # so we don't clutter up all controllers with non-interface methods.
3
5
  # This class is used internally, so you do not need to call methods directly on it.
4
6
  class ControllerResource # :nodoc:
5
- def self.add_before_filter(controller_class, method, *args)
7
+ include ControllerResourceLoader
8
+
9
+ def self.add_before_action(controller_class, method, *args)
6
10
  options = args.extract_options!
7
11
  resource_name = args.first
8
- before_filter_method = options.delete(:prepend) ? :prepend_before_filter : :before_filter
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)
12
+ before_action_method = before_callback_name(options)
13
+ controller_class.send(before_action_method, options.slice(:only, :except, :if, :unless)) do |controller|
14
+ controller.class.cancan_resource_class
15
+ .new(controller, resource_name, options.except(:only, :except, :if, :unless)).send(method)
11
16
  end
12
17
  end
13
18
 
19
+ def self.before_callback_name(options)
20
+ options.delete(:prepend) ? :prepend_before_action : :before_action
21
+ end
22
+
14
23
  def initialize(controller, *args)
15
24
  @controller = controller
16
25
  @params = controller.params
17
26
  @options = args.extract_options!
18
27
  @name = args.first
19
- raise CanCan::ImplementationRemoved, "The :nested option is no longer supported, instead use :through with separate load/authorize call." if @options[:nested]
20
- raise CanCan::ImplementationRemoved, "The :name option is no longer supported, instead pass the name as the first argument." if @options[:name]
21
- raise CanCan::ImplementationRemoved, "The :resource option has been renamed back to :class, use false if no class." if @options[:resource]
22
28
  end
23
29
 
24
30
  def load_and_authorize_resource
@@ -26,41 +32,37 @@ module CanCan
26
32
  authorize_resource
27
33
  end
28
34
 
29
- def load_resource
30
- unless skip?(:load)
31
- if load_instance?
32
- self.resource_instance ||= load_resource_instance
33
- elsif load_collection?
34
- self.collection_instance ||= load_collection
35
- end
36
- end
37
- end
38
-
39
35
  def authorize_resource
40
- unless skip?(:authorize)
41
- @controller.authorize!(authorization_action, resource_instance || resource_class_with_parent)
42
- end
36
+ return if skip?(:authorize)
37
+ @controller.authorize!(authorization_action, resource_instance || resource_class_with_parent)
43
38
  end
44
39
 
45
40
  def parent?
46
- @options.has_key?(:parent) ? @options[:parent] : @name && @name != name_from_controller.to_sym
41
+ @options.key?(:parent) ? @options[:parent] : @name && @name != name_from_controller.to_sym
47
42
  end
48
43
 
49
44
  def skip?(behavior)
50
- return false unless options = @controller.class.cancan_skipper[behavior][@name]
51
-
45
+ return false unless (options = @controller.class.cancan_skipper[behavior][@name])
52
46
  options == {} ||
53
- options[:except] && !action_exists_in?(options[:except]) ||
54
- action_exists_in?(options[:only])
47
+ options[:except] && !action_exists_in?(options[:except]) ||
48
+ action_exists_in?(options[:only])
55
49
  end
56
50
 
57
51
  protected
58
52
 
59
- def load_resource_instance
60
- if !parent? && new_actions.include?(@params[:action].to_sym)
61
- build_resource
62
- elsif id_param || @options[:singleton]
63
- find_resource
53
+ # Returns the class used for this resource. This can be overriden by the :class option.
54
+ # If +false+ is passed in it will use the resource name as a symbol in which case it should
55
+ # only be used for authorization, not loading since there's no class to load through.
56
+ def resource_class
57
+ case @options[:class]
58
+ when false
59
+ name.to_sym
60
+ when nil
61
+ namespaced_name.to_s.camelize.constantize
62
+ when String
63
+ @options[:class].constantize
64
+ else
65
+ @options[:class]
64
66
  end
65
67
  end
66
68
 
@@ -72,89 +74,14 @@ module CanCan
72
74
  resource_base.respond_to?(:accessible_by) && !current_ability.has_block?(authorization_action, resource_class)
73
75
  end
74
76
 
75
- def load_collection
76
- resource_base.accessible_by(current_ability, authorization_action)
77
- end
78
-
79
- def build_resource
80
- resource = resource_base.new(resource_params || {})
81
- assign_attributes(resource)
82
- end
83
-
84
- def assign_attributes(resource)
85
- resource.send("#{parent_name}=", parent_resource) if @options[:singleton] && parent_resource
86
- initial_attributes.each do |attr_name, value|
87
- resource.send("#{attr_name}=", value)
88
- end
89
- resource
90
- end
91
-
92
- def initial_attributes
93
- current_ability.attributes_for(@params[:action].to_sym, resource_class).delete_if do |key, value|
94
- resource_params && resource_params.include?(key)
95
- end
96
- end
97
-
98
- def find_resource
99
- if @options[:singleton] && parent_resource.respond_to?(name)
100
- parent_resource.send(name)
101
- else
102
- if @options[:find_by]
103
- if resource_base.respond_to? "find_by_#{@options[:find_by]}!"
104
- resource_base.send("find_by_#{@options[:find_by]}!", id_param)
105
- elsif resource_base.respond_to? "find_by"
106
- resource_base.send("find_by", { @options[:find_by].to_sym => id_param })
107
- else
108
- resource_base.send(@options[:find_by], id_param)
109
- end
110
- else
111
- adapter.find(resource_base, id_param)
112
- end
113
- end
114
- end
115
-
116
- def adapter
117
- ModelAdapters::AbstractAdapter.adapter_class(resource_class)
118
- end
119
-
120
- def authorization_action
121
- parent? ? parent_authorization_action : @params[:action].to_sym
122
- end
123
-
124
- def parent_authorization_action
125
- @options[:parent_action] || :show
126
- end
127
-
128
- def id_param
129
- @params[id_param_key].to_s if @params[id_param_key]
130
- end
131
-
132
- def id_param_key
133
- if @options[:id_param]
134
- @options[:id_param]
135
- else
136
- parent? ? :"#{name}_id" : :id
137
- end
138
- end
139
-
140
77
  def member_action?
141
- new_actions.include?(@params[:action].to_sym) || @options[:singleton] || ( (@params[:id] || @params[@options[:id_param]]) && !collection_actions.include?(@params[:action].to_sym))
142
- end
143
-
144
- # Returns the class used for this resource. This can be overriden by the :class option.
145
- # If +false+ is passed in it will use the resource name as a symbol in which case it should
146
- # only be used for authorization, not loading since there's no class to load through.
147
- def resource_class
148
- case @options[:class]
149
- when false then name.to_sym
150
- when nil then namespaced_name.to_s.camelize.constantize
151
- when String then @options[:class].constantize
152
- else @options[:class]
153
- end
78
+ new_actions.include?(@params[:action].to_sym) || @options[:singleton] ||
79
+ ((@params[:id] || @params[@options[:id_param]]) &&
80
+ !collection_actions.include?(@params[:action].to_sym))
154
81
  end
155
82
 
156
83
  def resource_class_with_parent
157
- parent_resource ? {parent_resource => resource_class} : resource_class
84
+ parent_resource ? { parent_resource => resource_class } : resource_class
158
85
  end
159
86
 
160
87
  def resource_instance=(instance)
@@ -162,7 +89,8 @@ module CanCan
162
89
  end
163
90
 
164
91
  def resource_instance
165
- @controller.instance_variable_get("@#{instance_name}") if load_instance?
92
+ return unless load_instance? && @controller.instance_variable_defined?("@#{instance_name}")
93
+ @controller.instance_variable_get("@#{instance_name}")
166
94
  end
167
95
 
168
96
  def collection_instance=(instance)
@@ -170,107 +98,14 @@ module CanCan
170
98
  end
171
99
 
172
100
  def collection_instance
101
+ return unless @controller.instance_variable_defined?("@#{instance_name.to_s.pluralize}")
173
102
  @controller.instance_variable_get("@#{instance_name.to_s.pluralize}")
174
103
  end
175
104
 
176
- # The object that methods (such as "find", "new" or "build") are called on.
177
- # If the :through option is passed it will go through an association on that instance.
178
- # If the :shallow option is passed it will use the resource_class if there's no parent
179
- # If the :singleton option is passed it won't use the association because it needs to be handled later.
180
- def resource_base
181
- if @options[:through]
182
- if parent_resource
183
- base = @options[:singleton] ? resource_class : parent_resource.send(@options[:through_association] || name.to_s.pluralize)
184
- base = base.scoped if base.respond_to?(:scoped) && defined?(ActiveRecord) && ActiveRecord::VERSION::MAJOR == 3
185
- base
186
- elsif @options[:shallow]
187
- resource_class
188
- else
189
- raise AccessDenied.new(nil, authorization_action, resource_class) # maybe this should be a record not found error instead?
190
- end
191
- else
192
- resource_class
193
- end
194
- end
195
-
196
- def parent_name
197
- @options[:through] && [@options[:through]].flatten.detect { |i| fetch_parent(i) }
198
- end
199
-
200
- # The object to load this resource through.
201
- def parent_resource
202
- parent_name && fetch_parent(parent_name)
203
- end
204
-
205
- def fetch_parent(name)
206
- if @controller.instance_variable_defined? "@#{name}"
207
- @controller.instance_variable_get("@#{name}")
208
- elsif @controller.respond_to?(name, true)
209
- @controller.send(name)
210
- end
211
- end
212
-
213
- def current_ability
214
- @controller.send(:current_ability)
215
- end
216
-
217
- def name
218
- @name || name_from_controller
219
- end
220
-
221
- def resource_params
222
- if parameters_require_sanitizing? && params_method.present?
223
- return case params_method
224
- when Symbol then @controller.send(params_method)
225
- when String then @controller.instance_eval(params_method)
226
- when Proc then params_method.call(@controller)
227
- end
228
- else
229
- resource_params_by_namespaced_name
230
- end
231
- end
232
-
233
105
  def parameters_require_sanitizing?
234
106
  save_actions.include?(@params[:action].to_sym) || resource_params_by_namespaced_name.present?
235
107
  end
236
108
 
237
- def resource_params_by_namespaced_name
238
- if @options[:instance_name] && @params.has_key?(extract_key(@options[:instance_name]))
239
- @params[extract_key(@options[:instance_name])]
240
- elsif @options[:class] && @params.has_key?(extract_key(@options[:class]))
241
- @params[extract_key(@options[:class])]
242
- else
243
- @params[extract_key(namespaced_name)]
244
- end
245
- end
246
-
247
- def params_method
248
- params_methods.each do |method|
249
- return method if (method.is_a?(Symbol) && @controller.respond_to?(method, true)) || method.is_a?(String) || method.is_a?(Proc)
250
- end
251
- nil
252
- end
253
-
254
- def params_methods
255
- methods = ["#{@params[:action]}_params".to_sym, "#{name}_params".to_sym, :resource_params]
256
- methods.unshift(@options[:param_method]) if @options[:param_method].present?
257
- methods
258
- end
259
-
260
- def namespace
261
- @params[:controller].split('/')[0..-2]
262
- end
263
-
264
- def namespaced_name
265
- [namespace, name.camelize].flatten.map(&:camelize).join('::').singularize.constantize
266
- rescue NameError
267
- name
268
- end
269
-
270
- def name_from_controller
271
- @params[:controller].split('/').last.singularize
272
- end
273
-
274
109
  def instance_name
275
110
  @options[:instance_name] || name
276
111
  end
@@ -279,12 +114,8 @@ module CanCan
279
114
  [:index] + Array(@options[:collection])
280
115
  end
281
116
 
282
- def new_actions
283
- [:new, :create] + Array(@options[:new])
284
- end
285
-
286
117
  def save_actions
287
- [:create, :update]
118
+ %i[create update]
288
119
  end
289
120
 
290
121
  private
@@ -293,8 +124,12 @@ module CanCan
293
124
  Array(options).include?(@params[:action].to_sym)
294
125
  end
295
126
 
296
- def extract_key(value)
297
- value.to_s.underscore.gsub('/', '_')
127
+ def adapter
128
+ ModelAdapters::AbstractAdapter.adapter_class(resource_class)
129
+ end
130
+
131
+ def current_ability
132
+ @controller.send(:current_ability)
298
133
  end
299
134
  end
300
135
  end
@@ -0,0 +1,24 @@
1
+ module CanCan
2
+ module ControllerResourceBuilder
3
+ protected
4
+
5
+ def build_resource
6
+ resource = resource_base.new(resource_params || {})
7
+ assign_attributes(resource)
8
+ end
9
+
10
+ def assign_attributes(resource)
11
+ resource.send("#{parent_name}=", parent_resource) if @options[:singleton] && parent_resource
12
+ initial_attributes.each do |attr_name, value|
13
+ resource.send("#{attr_name}=", value)
14
+ end
15
+ resource
16
+ end
17
+
18
+ def initial_attributes
19
+ current_ability.attributes_for(@params[:action].to_sym, resource_class).delete_if do |key, _value|
20
+ resource_params && resource_params.include?(key)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,40 @@
1
+ module CanCan
2
+ module ControllerResourceFinder
3
+ protected
4
+
5
+ def find_resource
6
+ if @options[:singleton] && parent_resource.respond_to?(name)
7
+ parent_resource.send(name)
8
+ elsif @options[:find_by]
9
+ find_resource_using_find_by
10
+ else
11
+ adapter.find(resource_base, id_param)
12
+ end
13
+ end
14
+
15
+ def find_resource_using_find_by
16
+ find_by_dynamic_finder || find_by_find_by_finder || resource_base.send(@options[:find_by], id_param)
17
+ end
18
+
19
+ def find_by_dynamic_finder
20
+ method_name = "find_by_#{@options[:find_by]}!"
21
+ resource_base.send(method_name, id_param) if resource_base.respond_to? method_name
22
+ end
23
+
24
+ def find_by_find_by_finder
25
+ resource_base.find_by(@options[:find_by].to_sym => id_param) if resource_base.respond_to? :find_by
26
+ end
27
+
28
+ def id_param
29
+ @params[id_param_key].to_s if @params[id_param_key].present?
30
+ end
31
+
32
+ def id_param_key
33
+ if @options[:id_param]
34
+ @options[:id_param]
35
+ else
36
+ parent? ? :"#{name}_id" : :id
37
+ end
38
+ end
39
+ end
40
+ end