cancancan 1.11.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
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