cancancan 2.1.0 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,8 +1,11 @@
1
+ require_relative 'controller_resource_loader.rb'
1
2
  module CanCan
2
3
  # Handle the load and authorization controller logic
3
4
  # so we don't clutter up all controllers with non-interface methods.
4
5
  # This class is used internally, so you do not need to call methods directly on it.
5
6
  class ControllerResource # :nodoc:
7
+ include ControllerResourceLoader
8
+
6
9
  def self.add_before_action(controller_class, method, *args)
7
10
  options = args.extract_options!
8
11
  resource_name = args.first
@@ -29,15 +32,6 @@ module CanCan
29
32
  authorize_resource
30
33
  end
31
34
 
32
- def load_resource
33
- return if skip?(:load)
34
- if load_instance?
35
- self.resource_instance ||= load_resource_instance
36
- elsif load_collection?
37
- self.collection_instance ||= load_collection
38
- end
39
- end
40
-
41
35
  def authorize_resource
42
36
  return if skip?(:authorize)
43
37
  @controller.authorize!(authorization_action, resource_instance || resource_class_with_parent)
@@ -56,11 +50,19 @@ module CanCan
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,95 +74,12 @@ 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
- elsif @options[:find_by]
102
- find_resource_using_find_by
103
- else
104
- adapter.find(resource_base, id_param)
105
- end
106
- end
107
-
108
- def find_resource_using_find_by
109
- if resource_base.respond_to? "find_by_#{@options[:find_by]}!"
110
- resource_base.send("find_by_#{@options[:find_by]}!", id_param)
111
- elsif resource_base.respond_to? 'find_by'
112
- resource_base.send('find_by', @options[:find_by].to_sym => id_param)
113
- else
114
- resource_base.send(@options[:find_by], id_param)
115
- end
116
- end
117
-
118
- def adapter
119
- ModelAdapters::AbstractAdapter.adapter_class(resource_class)
120
- end
121
-
122
- def authorization_action
123
- parent? ? parent_authorization_action : @params[:action].to_sym
124
- end
125
-
126
- def parent_authorization_action
127
- @options[:parent_action] || :show
128
- end
129
-
130
- def id_param
131
- @params[id_param_key].to_s if @params[id_param_key].present?
132
- end
133
-
134
- def id_param_key
135
- if @options[:id_param]
136
- @options[:id_param]
137
- else
138
- parent? ? :"#{name}_id" : :id
139
- end
140
- end
141
-
142
77
  def member_action?
143
78
  new_actions.include?(@params[:action].to_sym) || @options[:singleton] ||
144
79
  ((@params[:id] || @params[@options[:id_param]]) &&
145
80
  !collection_actions.include?(@params[:action].to_sym))
146
81
  end
147
82
 
148
- # Returns the class used for this resource. This can be overriden by the :class option.
149
- # If +false+ is passed in it will use the resource name as a symbol in which case it should
150
- # only be used for authorization, not loading since there's no class to load through.
151
- def resource_class
152
- case @options[:class]
153
- when false then
154
- name.to_sym
155
- when nil then
156
- namespaced_name.to_s.camelize.constantize
157
- when String then
158
- @options[:class].constantize
159
- else
160
- @options[:class]
161
- end
162
- end
163
-
164
83
  def resource_class_with_parent
165
84
  parent_resource ? { parent_resource => resource_class } : resource_class
166
85
  end
@@ -183,114 +102,10 @@ module CanCan
183
102
  @controller.instance_variable_get("@#{instance_name.to_s.pluralize}")
184
103
  end
185
104
 
186
- # The object that methods (such as "find", "new" or "build") are called on.
187
- # If the :through option is passed it will go through an association on that instance.
188
- # If the :shallow option is passed it will use the resource_class if there's no parent
189
- # If the :singleton option is passed it won't use the association because it needs to be handled later.
190
- def resource_base
191
- if @options[:through]
192
- resource_base_through
193
- else
194
- resource_class
195
- end
196
- end
197
-
198
- def resource_base_through
199
- if parent_resource
200
- if @options[:singleton]
201
- resource_class
202
- else
203
- parent_resource.send(@options[:through_association] || name.to_s.pluralize)
204
- end
205
- elsif @options[:shallow]
206
- resource_class
207
- else
208
- # maybe this should be a record not found error instead?
209
- raise AccessDenied.new(nil, authorization_action, resource_class)
210
- end
211
- end
212
-
213
- def parent_name
214
- @options[:through] && [@options[:through]].flatten.detect { |i| fetch_parent(i) }
215
- end
216
-
217
- # The object to load this resource through.
218
- def parent_resource
219
- parent_name && fetch_parent(parent_name)
220
- end
221
-
222
- def fetch_parent(name)
223
- if @controller.instance_variable_defined? "@#{name}"
224
- @controller.instance_variable_get("@#{name}")
225
- elsif @controller.respond_to?(name, true)
226
- @controller.send(name)
227
- end
228
- end
229
-
230
- def current_ability
231
- @controller.send(:current_ability)
232
- end
233
-
234
- def name
235
- @name || name_from_controller
236
- end
237
-
238
- def resource_params
239
- if parameters_require_sanitizing? && params_method.present?
240
- case params_method
241
- when Symbol then
242
- @controller.send(params_method)
243
- when String then
244
- @controller.instance_eval(params_method)
245
- when Proc then
246
- params_method.call(@controller)
247
- end
248
- else
249
- resource_params_by_namespaced_name
250
- end
251
- end
252
-
253
105
  def parameters_require_sanitizing?
254
106
  save_actions.include?(@params[:action].to_sym) || resource_params_by_namespaced_name.present?
255
107
  end
256
108
 
257
- def resource_params_by_namespaced_name
258
- if @options[:instance_name] && @params.key?(extract_key(@options[:instance_name]))
259
- @params[extract_key(@options[:instance_name])]
260
- elsif @options[:class] && @params.key?(extract_key(@options[:class]))
261
- @params[extract_key(@options[:class])]
262
- else
263
- params = @params[extract_key(namespaced_name)]
264
- params.is_a?(Hash) ? params : nil
265
- end
266
- end
267
-
268
- def params_method
269
- params_methods.each do |method|
270
- return method if (method.is_a?(Symbol) && @controller.respond_to?(method, true)) ||
271
- method.is_a?(String) || method.is_a?(Proc)
272
- end
273
- nil
274
- end
275
-
276
- def params_methods
277
- methods = ["#{@params[:action]}_params".to_sym, "#{name}_params".to_sym, :resource_params]
278
- methods.unshift(@options[:param_method]) if @options[:param_method].present?
279
- methods
280
- end
281
-
282
- def namespace
283
- @params[:controller].split('/')[0..-2]
284
- end
285
-
286
- def namespaced_name
287
- [namespace, name].join('/').singularize.camelize.safe_constantize || name
288
- end
289
-
290
- def name_from_controller
291
- @params[:controller].split('/').last.singularize
292
- end
293
-
294
109
  def instance_name
295
110
  @options[:instance_name] || name
296
111
  end
@@ -299,10 +114,6 @@ module CanCan
299
114
  [:index] + Array(@options[:collection])
300
115
  end
301
116
 
302
- def new_actions
303
- %i[new create] + Array(@options[:new])
304
- end
305
-
306
117
  def save_actions
307
118
  %i[create update]
308
119
  end
@@ -313,8 +124,12 @@ module CanCan
313
124
  Array(options).include?(@params[:action].to_sym)
314
125
  end
315
126
 
316
- def extract_key(value)
317
- value.to_s.underscore.tr('/', '_')
127
+ def adapter
128
+ ModelAdapters::AbstractAdapter.adapter_class(resource_class)
129
+ end
130
+
131
+ def current_ability
132
+ @controller.send(:current_ability)
318
133
  end
319
134
  end
320
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,35 @@
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
+ if resource_base.respond_to? 'find_by'
17
+ resource_base.send('find_by', @options[:find_by].to_sym => id_param)
18
+ else
19
+ resource_base.send(@options[:find_by], id_param)
20
+ end
21
+ end
22
+
23
+ def id_param
24
+ @params[id_param_key].to_s if @params[id_param_key].present?
25
+ end
26
+
27
+ def id_param_key
28
+ if @options[:id_param]
29
+ @options[:id_param]
30
+ else
31
+ parent? ? :"#{name}_id" : :id
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,116 @@
1
+ require_relative 'controller_resource_finder.rb'
2
+ require_relative 'controller_resource_name_finder.rb'
3
+ require_relative 'controller_resource_builder.rb'
4
+ require_relative 'controller_resource_sanitizer.rb'
5
+ module CanCan
6
+ module ControllerResourceLoader
7
+ include CanCan::ControllerResourceNameFinder
8
+ include CanCan::ControllerResourceFinder
9
+ include CanCan::ControllerResourceBuilder
10
+ include CanCan::ControllerResourceSanitizer
11
+
12
+ def load_resource
13
+ return if skip?(:load)
14
+ if load_instance?
15
+ self.resource_instance ||= load_resource_instance
16
+ elsif load_collection?
17
+ self.collection_instance ||= load_collection
18
+ end
19
+ end
20
+
21
+ protected
22
+
23
+ def new_actions
24
+ %i[new create] + Array(@options[:new])
25
+ end
26
+
27
+ def resource_params_by_key(key)
28
+ return unless @options[key] && @params.key?(extract_key(@options[key]))
29
+ @params[extract_key(@options[key])]
30
+ end
31
+
32
+ def resource_params_by_namespaced_name
33
+ resource_params_by_key(:instance_name) || resource_params_by_key(:class) || (
34
+ params = @params[extract_key(namespaced_name)]
35
+ params.respond_to?(:to_h) ? params : nil)
36
+ end
37
+
38
+ def resource_params
39
+ if parameters_require_sanitizing? && params_method.present?
40
+ sanitize_parameters
41
+ else
42
+ resource_params_by_namespaced_name
43
+ end
44
+ end
45
+
46
+ def fetch_parent(name)
47
+ if @controller.instance_variable_defined? "@#{name}"
48
+ @controller.instance_variable_get("@#{name}")
49
+ elsif @controller.respond_to?(name, true)
50
+ @controller.send(name)
51
+ end
52
+ end
53
+
54
+ # The object to load this resource through.
55
+ def parent_resource
56
+ parent_name && fetch_parent(parent_name)
57
+ end
58
+
59
+ def parent_name
60
+ @options[:through] && [@options[:through]].flatten.detect { |i| fetch_parent(i) }
61
+ end
62
+
63
+ def resource_base_through_parent_resource
64
+ if @options[:singleton]
65
+ resource_class
66
+ else
67
+ parent_resource.send(@options[:through_association] || name.to_s.pluralize)
68
+ end
69
+ end
70
+
71
+ def resource_base_through
72
+ if parent_resource
73
+ resource_base_through_parent_resource
74
+ elsif @options[:shallow]
75
+ resource_class
76
+ else
77
+ # maybe this should be a record not found error instead?
78
+ raise AccessDenied.new(nil, authorization_action, resource_class)
79
+ end
80
+ end
81
+
82
+ # The object that methods (such as "find", "new" or "build") are called on.
83
+ # If the :through option is passed it will go through an association on that instance.
84
+ # If the :shallow option is passed it will use the resource_class if there's no parent
85
+ # If the :singleton option is passed it won't use the association because it needs to be handled later.
86
+ def resource_base
87
+ @options[:through] ? resource_base_through : resource_class
88
+ end
89
+
90
+ def parent_authorization_action
91
+ @options[:parent_action] || :show
92
+ end
93
+
94
+ def authorization_action
95
+ parent? ? parent_authorization_action : @params[:action].to_sym
96
+ end
97
+
98
+ def load_collection
99
+ resource_base.accessible_by(current_ability, authorization_action)
100
+ end
101
+
102
+ def load_resource_instance
103
+ if !parent? && new_actions.include?(@params[:action].to_sym)
104
+ build_resource
105
+ elsif id_param || @options[:singleton]
106
+ find_resource
107
+ end
108
+ end
109
+
110
+ private
111
+
112
+ def extract_key(value)
113
+ value.to_s.underscore.tr('/', '_')
114
+ end
115
+ end
116
+ end