cancancan 1.13.1 → 3.1.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.
- checksums.yaml +5 -5
- data/cancancan.gemspec +18 -18
- data/init.rb +2 -0
- data/lib/cancan.rb +9 -11
- data/lib/cancan/ability.rb +93 -194
- data/lib/cancan/ability/actions.rb +93 -0
- data/lib/cancan/ability/rules.rb +93 -0
- data/lib/cancan/ability/strong_parameter_support.rb +41 -0
- data/lib/cancan/conditions_matcher.rb +106 -0
- data/lib/cancan/controller_additions.rb +38 -41
- data/lib/cancan/controller_resource.rb +52 -211
- data/lib/cancan/controller_resource_builder.rb +26 -0
- data/lib/cancan/controller_resource_finder.rb +42 -0
- data/lib/cancan/controller_resource_loader.rb +120 -0
- data/lib/cancan/controller_resource_name_finder.rb +23 -0
- data/lib/cancan/controller_resource_sanitizer.rb +32 -0
- data/lib/cancan/exceptions.rb +17 -5
- data/lib/cancan/matchers.rb +12 -3
- data/lib/cancan/model_adapters/abstract_adapter.rb +10 -8
- data/lib/cancan/model_adapters/active_record_4_adapter.rb +39 -13
- data/lib/cancan/model_adapters/active_record_5_adapter.rb +68 -0
- data/lib/cancan/model_adapters/active_record_adapter.rb +77 -82
- data/lib/cancan/model_adapters/conditions_extractor.rb +75 -0
- data/lib/cancan/model_adapters/conditions_normalizer.rb +49 -0
- data/lib/cancan/model_adapters/default_adapter.rb +2 -0
- data/lib/cancan/model_additions.rb +2 -1
- data/lib/cancan/parameter_validators.rb +9 -0
- data/lib/cancan/relevant.rb +29 -0
- data/lib/cancan/rule.rb +76 -105
- data/lib/cancan/rules_compressor.rb +23 -0
- data/lib/cancan/unauthorized_message_resolver.rb +24 -0
- data/lib/cancan/version.rb +3 -1
- data/lib/cancancan.rb +2 -0
- data/lib/generators/cancan/ability/ability_generator.rb +4 -2
- data/lib/generators/cancan/ability/templates/ability.rb +2 -0
- metadata +66 -56
- data/.gitignore +0 -15
- data/.rspec +0 -1
- data/.travis.yml +0 -28
- data/Appraisals +0 -81
- data/CHANGELOG.rdoc +0 -518
- data/CONTRIBUTING.md +0 -23
- data/Gemfile +0 -3
- data/LICENSE +0 -22
- data/README.md +0 -214
- data/Rakefile +0 -9
- data/gemfiles/activerecord_3.2.gemfile +0 -16
- data/gemfiles/activerecord_4.0.gemfile +0 -17
- data/gemfiles/activerecord_4.1.gemfile +0 -17
- data/gemfiles/activerecord_4.2.gemfile +0 -18
- data/gemfiles/mongoid_2.x.gemfile +0 -16
- data/gemfiles/sequel_3.x.gemfile +0 -16
- data/lib/cancan/inherited_resource.rb +0 -20
- data/lib/cancan/model_adapters/active_record_3_adapter.rb +0 -16
- data/lib/cancan/model_adapters/mongoid_adapter.rb +0 -54
- data/lib/cancan/model_adapters/sequel_adapter.rb +0 -87
- data/spec/README.rdoc +0 -27
- data/spec/cancan/ability_spec.rb +0 -521
- data/spec/cancan/controller_additions_spec.rb +0 -141
- data/spec/cancan/controller_resource_spec.rb +0 -632
- data/spec/cancan/exceptions_spec.rb +0 -58
- data/spec/cancan/inherited_resource_spec.rb +0 -71
- data/spec/cancan/matchers_spec.rb +0 -29
- data/spec/cancan/model_adapters/active_record_4_adapter_spec.rb +0 -85
- data/spec/cancan/model_adapters/active_record_adapter_spec.rb +0 -384
- data/spec/cancan/model_adapters/default_adapter_spec.rb +0 -7
- data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +0 -227
- data/spec/cancan/model_adapters/sequel_adapter_spec.rb +0 -132
- data/spec/cancan/rule_spec.rb +0 -52
- data/spec/matchers.rb +0 -13
- data/spec/spec.opts +0 -2
- data/spec/spec_helper.rb +0 -27
- data/spec/support/ability.rb +0 -7
@@ -1,24 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'controller_resource_loader.rb'
|
1
4
|
module CanCan
|
2
|
-
# Handle the load and authorization controller logic
|
5
|
+
# Handle the load and authorization controller logic
|
6
|
+
# so we don't clutter up all controllers with non-interface methods.
|
3
7
|
# This class is used internally, so you do not need to call methods directly on it.
|
4
8
|
class ControllerResource # :nodoc:
|
5
|
-
|
9
|
+
include ControllerResourceLoader
|
10
|
+
|
11
|
+
def self.add_before_action(controller_class, method, *args)
|
6
12
|
options = args.extract_options!
|
7
13
|
resource_name = args.first
|
8
|
-
|
9
|
-
controller_class.send(
|
10
|
-
controller.class.cancan_resource_class
|
14
|
+
before_action_method = before_callback_name(options)
|
15
|
+
controller_class.send(before_action_method, options.slice(:only, :except, :if, :unless)) do |controller|
|
16
|
+
controller.class.cancan_resource_class
|
17
|
+
.new(controller, resource_name, options.except(:only, :except, :if, :unless)).send(method)
|
11
18
|
end
|
12
19
|
end
|
13
20
|
|
21
|
+
def self.before_callback_name(options)
|
22
|
+
options.delete(:prepend) ? :prepend_before_action : :before_action
|
23
|
+
end
|
24
|
+
|
14
25
|
def initialize(controller, *args)
|
15
26
|
@controller = controller
|
16
27
|
@params = controller.params
|
17
28
|
@options = args.extract_options!
|
18
29
|
@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
30
|
end
|
23
31
|
|
24
32
|
def load_and_authorize_resource
|
@@ -26,41 +34,39 @@ module CanCan
|
|
26
34
|
authorize_resource
|
27
35
|
end
|
28
36
|
|
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
37
|
def authorize_resource
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
return if skip?(:authorize)
|
39
|
+
|
40
|
+
@controller.authorize!(authorization_action, resource_instance || resource_class_with_parent)
|
43
41
|
end
|
44
42
|
|
45
43
|
def parent?
|
46
|
-
@options.
|
44
|
+
@options.key?(:parent) ? @options[:parent] : @name && @name != name_from_controller.to_sym
|
47
45
|
end
|
48
46
|
|
49
47
|
def skip?(behavior)
|
50
|
-
return false unless options = @controller.class.cancan_skipper[behavior][@name]
|
48
|
+
return false unless (options = @controller.class.cancan_skipper[behavior][@name])
|
51
49
|
|
52
50
|
options == {} ||
|
53
|
-
|
54
|
-
|
51
|
+
options[:except] && !action_exists_in?(options[:except]) ||
|
52
|
+
action_exists_in?(options[:only])
|
55
53
|
end
|
56
54
|
|
57
55
|
protected
|
58
56
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
57
|
+
# Returns the class used for this resource. This can be overriden by the :class option.
|
58
|
+
# If +false+ is passed in it will use the resource name as a symbol in which case it should
|
59
|
+
# only be used for authorization, not loading since there's no class to load through.
|
60
|
+
def resource_class
|
61
|
+
case @options[:class]
|
62
|
+
when false
|
63
|
+
name.to_sym
|
64
|
+
when nil
|
65
|
+
namespaced_name.to_s.camelize.constantize
|
66
|
+
when String
|
67
|
+
@options[:class].constantize
|
68
|
+
else
|
69
|
+
@options[:class]
|
64
70
|
end
|
65
71
|
end
|
66
72
|
|
@@ -72,89 +78,14 @@ module CanCan
|
|
72
78
|
resource_base.respond_to?(:accessible_by) && !current_ability.has_block?(authorization_action, resource_class)
|
73
79
|
end
|
74
80
|
|
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
81
|
def member_action?
|
141
|
-
new_actions.include?(@params[:action].to_sym) || @options[:singleton] ||
|
142
|
-
|
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
|
82
|
+
new_actions.include?(@params[:action].to_sym) || @options[:singleton] ||
|
83
|
+
((@params[:id] || @params[@options[:id_param]]) &&
|
84
|
+
!collection_actions.include?(@params[:action].to_sym))
|
154
85
|
end
|
155
86
|
|
156
87
|
def resource_class_with_parent
|
157
|
-
parent_resource ? {parent_resource => resource_class} : resource_class
|
88
|
+
parent_resource ? { parent_resource => resource_class } : resource_class
|
158
89
|
end
|
159
90
|
|
160
91
|
def resource_instance=(instance)
|
@@ -162,7 +93,9 @@ module CanCan
|
|
162
93
|
end
|
163
94
|
|
164
95
|
def resource_instance
|
165
|
-
@controller.
|
96
|
+
return unless load_instance? && @controller.instance_variable_defined?("@#{instance_name}")
|
97
|
+
|
98
|
+
@controller.instance_variable_get("@#{instance_name}")
|
166
99
|
end
|
167
100
|
|
168
101
|
def collection_instance=(instance)
|
@@ -170,107 +103,15 @@ module CanCan
|
|
170
103
|
end
|
171
104
|
|
172
105
|
def collection_instance
|
173
|
-
@controller.
|
174
|
-
end
|
175
|
-
|
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
|
106
|
+
return unless @controller.instance_variable_defined?("@#{instance_name.to_s.pluralize}")
|
220
107
|
|
221
|
-
|
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
|
108
|
+
@controller.instance_variable_get("@#{instance_name.to_s.pluralize}")
|
231
109
|
end
|
232
110
|
|
233
111
|
def parameters_require_sanitizing?
|
234
112
|
save_actions.include?(@params[:action].to_sym) || resource_params_by_namespaced_name.present?
|
235
113
|
end
|
236
114
|
|
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
115
|
def instance_name
|
275
116
|
@options[:instance_name] || name
|
276
117
|
end
|
@@ -279,12 +120,8 @@ module CanCan
|
|
279
120
|
[:index] + Array(@options[:collection])
|
280
121
|
end
|
281
122
|
|
282
|
-
def new_actions
|
283
|
-
[:new, :create] + Array(@options[:new])
|
284
|
-
end
|
285
|
-
|
286
123
|
def save_actions
|
287
|
-
[
|
124
|
+
%i[create update]
|
288
125
|
end
|
289
126
|
|
290
127
|
private
|
@@ -293,8 +130,12 @@ module CanCan
|
|
293
130
|
Array(options).include?(@params[:action].to_sym)
|
294
131
|
end
|
295
132
|
|
296
|
-
def
|
297
|
-
|
133
|
+
def adapter
|
134
|
+
ModelAdapters::AbstractAdapter.adapter_class(resource_class)
|
135
|
+
end
|
136
|
+
|
137
|
+
def current_ability
|
138
|
+
@controller.send(:current_ability)
|
298
139
|
end
|
299
140
|
end
|
300
141
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CanCan
|
4
|
+
module ControllerResourceBuilder
|
5
|
+
protected
|
6
|
+
|
7
|
+
def build_resource
|
8
|
+
resource = resource_base.new(resource_params || {})
|
9
|
+
assign_attributes(resource)
|
10
|
+
end
|
11
|
+
|
12
|
+
def assign_attributes(resource)
|
13
|
+
resource.send("#{parent_name}=", parent_resource) if @options[:singleton] && parent_resource
|
14
|
+
initial_attributes.each do |attr_name, value|
|
15
|
+
resource.send("#{attr_name}=", value)
|
16
|
+
end
|
17
|
+
resource
|
18
|
+
end
|
19
|
+
|
20
|
+
def initial_attributes
|
21
|
+
current_ability.attributes_for(@params[:action].to_sym, resource_class).delete_if do |key, _value|
|
22
|
+
resource_params && resource_params.include?(key)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CanCan
|
4
|
+
module ControllerResourceFinder
|
5
|
+
protected
|
6
|
+
|
7
|
+
def find_resource
|
8
|
+
if @options[:singleton] && parent_resource.respond_to?(name)
|
9
|
+
parent_resource.send(name)
|
10
|
+
elsif @options[:find_by]
|
11
|
+
find_resource_using_find_by
|
12
|
+
else
|
13
|
+
adapter.find(resource_base, id_param)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def find_resource_using_find_by
|
18
|
+
find_by_dynamic_finder || find_by_find_by_finder || resource_base.send(@options[:find_by], id_param)
|
19
|
+
end
|
20
|
+
|
21
|
+
def find_by_dynamic_finder
|
22
|
+
method_name = "find_by_#{@options[:find_by]}!"
|
23
|
+
resource_base.send(method_name, id_param) if resource_base.respond_to? method_name
|
24
|
+
end
|
25
|
+
|
26
|
+
def find_by_find_by_finder
|
27
|
+
resource_base.find_by(@options[:find_by].to_sym => id_param) if resource_base.respond_to? :find_by
|
28
|
+
end
|
29
|
+
|
30
|
+
def id_param
|
31
|
+
@params[id_param_key].to_s if @params[id_param_key].present?
|
32
|
+
end
|
33
|
+
|
34
|
+
def id_param_key
|
35
|
+
if @options[:id_param]
|
36
|
+
@options[:id_param]
|
37
|
+
else
|
38
|
+
parent? ? :"#{name}_id" : :id
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'controller_resource_finder.rb'
|
4
|
+
require_relative 'controller_resource_name_finder.rb'
|
5
|
+
require_relative 'controller_resource_builder.rb'
|
6
|
+
require_relative 'controller_resource_sanitizer.rb'
|
7
|
+
module CanCan
|
8
|
+
module ControllerResourceLoader
|
9
|
+
include CanCan::ControllerResourceNameFinder
|
10
|
+
include CanCan::ControllerResourceFinder
|
11
|
+
include CanCan::ControllerResourceBuilder
|
12
|
+
include CanCan::ControllerResourceSanitizer
|
13
|
+
|
14
|
+
def load_resource
|
15
|
+
return if skip?(:load)
|
16
|
+
|
17
|
+
if load_instance?
|
18
|
+
self.resource_instance ||= load_resource_instance
|
19
|
+
elsif load_collection?
|
20
|
+
self.collection_instance ||= load_collection
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def new_actions
|
27
|
+
%i[new create] + Array(@options[:new])
|
28
|
+
end
|
29
|
+
|
30
|
+
def resource_params_by_key(key)
|
31
|
+
return unless @options[key] && @params.key?(extract_key(@options[key]))
|
32
|
+
|
33
|
+
@params[extract_key(@options[key])]
|
34
|
+
end
|
35
|
+
|
36
|
+
def resource_params_by_namespaced_name
|
37
|
+
resource_params_by_key(:instance_name) || resource_params_by_key(:class) || (
|
38
|
+
params = @params[extract_key(namespaced_name)]
|
39
|
+
params.respond_to?(:to_h) ? params : nil)
|
40
|
+
end
|
41
|
+
|
42
|
+
def resource_params
|
43
|
+
if parameters_require_sanitizing? && params_method.present?
|
44
|
+
sanitize_parameters
|
45
|
+
else
|
46
|
+
resource_params_by_namespaced_name
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def fetch_parent(name)
|
51
|
+
if @controller.instance_variable_defined? "@#{name}"
|
52
|
+
@controller.instance_variable_get("@#{name}")
|
53
|
+
elsif @controller.respond_to?(name, true)
|
54
|
+
@controller.send(name)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# The object to load this resource through.
|
59
|
+
def parent_resource
|
60
|
+
parent_name && fetch_parent(parent_name)
|
61
|
+
end
|
62
|
+
|
63
|
+
def parent_name
|
64
|
+
@options[:through] && [@options[:through]].flatten.detect { |i| fetch_parent(i) }
|
65
|
+
end
|
66
|
+
|
67
|
+
def resource_base_through_parent_resource
|
68
|
+
if @options[:singleton]
|
69
|
+
resource_class
|
70
|
+
else
|
71
|
+
parent_resource.send(@options[:through_association] || name.to_s.pluralize)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def resource_base_through
|
76
|
+
if parent_resource
|
77
|
+
resource_base_through_parent_resource
|
78
|
+
elsif @options[:shallow]
|
79
|
+
resource_class
|
80
|
+
else
|
81
|
+
# maybe this should be a record not found error instead?
|
82
|
+
raise AccessDenied.new(nil, authorization_action, resource_class)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# The object that methods (such as "find", "new" or "build") are called on.
|
87
|
+
# If the :through option is passed it will go through an association on that instance.
|
88
|
+
# If the :shallow option is passed it will use the resource_class if there's no parent
|
89
|
+
# If the :singleton option is passed it won't use the association because it needs to be handled later.
|
90
|
+
def resource_base
|
91
|
+
@options[:through] ? resource_base_through : resource_class
|
92
|
+
end
|
93
|
+
|
94
|
+
def parent_authorization_action
|
95
|
+
@options[:parent_action] || :show
|
96
|
+
end
|
97
|
+
|
98
|
+
def authorization_action
|
99
|
+
parent? ? parent_authorization_action : @params[:action].to_sym
|
100
|
+
end
|
101
|
+
|
102
|
+
def load_collection
|
103
|
+
resource_base.accessible_by(current_ability, authorization_action)
|
104
|
+
end
|
105
|
+
|
106
|
+
def load_resource_instance
|
107
|
+
if !parent? && new_actions.include?(@params[:action].to_sym)
|
108
|
+
build_resource
|
109
|
+
elsif id_param || @options[:singleton]
|
110
|
+
find_resource
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def extract_key(value)
|
117
|
+
value.to_s.underscore.tr('/', '_')
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|