cancancan_resource_controller 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/cancancan/abstract_resource_controller.rb +440 -0
- data/lib/cancancan_resource_controller.rb +4 -0
- metadata +149 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a38bfb98462e336b34961d82c4d130022bf466971f55c11699e707b7e6ce4fff
|
4
|
+
data.tar.gz: aa0be9ebb6885fc7b15156d0517f1df7c236c3da081a8cf01f6e5b3bf1b456ba
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 565013e091449c0a17c33413b7c2c7be15bb660ec644cda55db34df9310cdb7a3b94a3639b256df1745390b1cebc976d121eae3efe39bfe85954f75ef6a4af55
|
7
|
+
data.tar.gz: d7b727d66c11e8cf171e2eb6ba0f5175740b8be186ef0e463782e0a619951ccffca6f83fa4a50576d6ebf406629b77a840f74a5ad57b1344ea20fdce8eb3ddd9
|
@@ -0,0 +1,440 @@
|
|
1
|
+
# How to utilize CanCan Permissions to work with this controller:
|
2
|
+
module CanCanCan
|
3
|
+
module AbstractResourceController
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
before_action :initialize_resource_class
|
8
|
+
end
|
9
|
+
|
10
|
+
# Used to stop infinite recursive on associations (could just be deeply nested structures. Could also be self-referencing).
|
11
|
+
MAX_ASSOCIATIVE_NESTED_DEPTH = 60
|
12
|
+
REGEX_FOR_HTML_TAG_DETECTION = /.*\<\/?[^_\W]+\>.*/
|
13
|
+
|
14
|
+
# to handle adding/removing associations by "_ids" suffix
|
15
|
+
IDS_ATTIB_PERMISSION_KEY_GEN = Proc.new { |assoc_key| "#{assoc_key.to_s.singularize}_ids".to_sym }
|
16
|
+
IDS_ACTION_PERMISSION_KEY_GEN = Proc.new { |assoc_key| "_can_add_or_remove_association_#{assoc_key.to_s}".to_sym }
|
17
|
+
|
18
|
+
# to handle updating nested attributes
|
19
|
+
NESTED_ATTIB_PERMISSION_KEY_GEN = Proc.new { |assoc_key| "#{assoc_key.to_s}_attributes".to_sym }
|
20
|
+
NESTED_ACTION_PERMISSION_KEY_GEN = Proc.new { |assoc_key| "_can_update_association_#{assoc_key.to_s}".to_sym }
|
21
|
+
|
22
|
+
# For Read-Only fields
|
23
|
+
# - define this on your class model
|
24
|
+
# optional allowlist for incoming parameters for the implemented resource
|
25
|
+
# - nil means allowlist is inactive, acceptable parameters are determined by cancan attrib permissions
|
26
|
+
# - [] (empty array) means that no parameters will be accepted for resource
|
27
|
+
# - [<param1>, <param2>, ...] is self-explanatory, only those listed will be accepted
|
28
|
+
# class Resource
|
29
|
+
# RESOURCE_CONTROLLER_ATTRIB_ALLOWLIST = nil
|
30
|
+
# end
|
31
|
+
|
32
|
+
# probably a better way to do this. If there is, it's poorly documented.
|
33
|
+
# - src: https://www.w3schools.com/TAGS/default.ASP
|
34
|
+
# DEFAULT_PARAMETER_SANITIZER_ALLOWED_TAGS - Add to this env var any values to also allow for HTML tags (i.e.: label,span,text_area)
|
35
|
+
# DEFAULT_PARAMETER_SANITIZER_ALLOWED_ATTRIBS - Add to this env var any values to also allow for HTML attribs (i.e.: ng-show,ng-hide,data-id)
|
36
|
+
DEFAULT_PARAMETER_SANITIZER_ALLOWED_TAGS = (
|
37
|
+
%w[
|
38
|
+
p
|
39
|
+
div
|
40
|
+
span
|
41
|
+
body
|
42
|
+
b
|
43
|
+
strong
|
44
|
+
br
|
45
|
+
center
|
46
|
+
font
|
47
|
+
label
|
48
|
+
pre
|
49
|
+
tr
|
50
|
+
td
|
51
|
+
table
|
52
|
+
text_area
|
53
|
+
ul
|
54
|
+
li
|
55
|
+
footer
|
56
|
+
em
|
57
|
+
ol
|
58
|
+
i
|
59
|
+
select
|
60
|
+
option
|
61
|
+
] + (ENV['DEFAULT_PARAMETER_SANITIZER_ALLOWED_TAGS']&.split(',')&.collect(&:strip) || [])
|
62
|
+
).freeze
|
63
|
+
# Only allow attribs that are allowed in HTML friendly text blocks
|
64
|
+
# - i.e. NO HREFs!
|
65
|
+
DEFAULT_PARAMETER_SANITIZER_ALLOWED_ATTRIBS = (
|
66
|
+
%w[
|
67
|
+
style
|
68
|
+
id
|
69
|
+
class
|
70
|
+
type
|
71
|
+
value
|
72
|
+
] + (ENV['DEFAULT_PARAMETER_SANITIZER_ALLOWED_ATTRIBS']&.split(',')&.collect(&:strip) || [])
|
73
|
+
).freeze
|
74
|
+
|
75
|
+
def index
|
76
|
+
authorize! :index, @resource_class
|
77
|
+
@resources ||= @resource_class
|
78
|
+
|
79
|
+
begin
|
80
|
+
@resources = @resources.accessible_by(current_ability)
|
81
|
+
rescue CanCan::Error => e
|
82
|
+
# The accessible_by call cannot be used with a block 'can' definition
|
83
|
+
# Need to switch over to SQL permissions, not using the blocks
|
84
|
+
Rails.logger.error "Error: resource class, #{@resource_class.name}, is using CanCan block definitions, not SQL permissions. Unable to run index permission filter"
|
85
|
+
raise e
|
86
|
+
end
|
87
|
+
|
88
|
+
@resources = index_resource_query(@resources)
|
89
|
+
|
90
|
+
respond_with_resources
|
91
|
+
end
|
92
|
+
|
93
|
+
def show
|
94
|
+
authorize! :show, @resource_class
|
95
|
+
# Allow @resource to be set from subclass controller
|
96
|
+
@resource ||= @resource_class.find(params[:id])
|
97
|
+
authorize! :show, @resource
|
98
|
+
|
99
|
+
respond_with_resource
|
100
|
+
end
|
101
|
+
|
102
|
+
def new
|
103
|
+
authorize! :create, @resource_class
|
104
|
+
@resource ||= @resource_class.new(resource_params)
|
105
|
+
# 2nd auth on the object itself
|
106
|
+
# Not authing on the nested resources, that could have come in as nested attributes.
|
107
|
+
authorize! :create, @resource
|
108
|
+
|
109
|
+
respond_with_resource
|
110
|
+
end
|
111
|
+
|
112
|
+
def edit
|
113
|
+
authorize! :update, @resource_class
|
114
|
+
@resource ||= @resource_class.find(params[:id])
|
115
|
+
authorize! :update, @resource
|
116
|
+
|
117
|
+
respond_to do |format|
|
118
|
+
format.html # Renders the default
|
119
|
+
format.json { render json: @resources }
|
120
|
+
format.xml { render xml: @resources }
|
121
|
+
format.csv # Renders the default
|
122
|
+
format.xlsx # Renders the default
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def create
|
127
|
+
authorize! :create, @resource_class
|
128
|
+
# @resource = @resource_class.new(resource_params)
|
129
|
+
|
130
|
+
# This 2nd @resource initiation is so we run run whitelisting attribs on the object.
|
131
|
+
# Class whitelisting is far more broad than object attrib whitelisting.
|
132
|
+
# Necessary if class permissions have a permissions-block.
|
133
|
+
@resource ||= @resource_class.new(resource_params(@resource))
|
134
|
+
|
135
|
+
# 2nd auth on the object itself
|
136
|
+
authorize! :create, @resource
|
137
|
+
|
138
|
+
if @resource.save
|
139
|
+
respond_with_resource
|
140
|
+
else
|
141
|
+
begin
|
142
|
+
Rails.logger.warn "Failed object validations: could not create #{@resource_class}, id: #{@resource.id}: #{@resource.errors.full_messages}"
|
143
|
+
respond_with_resource_invalid
|
144
|
+
rescue Exception => e
|
145
|
+
Rails.logger.error "CanCanCanResourceController - Caught Internal Server Error: " + e.class.to_s + ': ' + e.message
|
146
|
+
Rails.logger.error Rails.backtrace_cleaner.clean(e.backtrace).join("\n").to_s
|
147
|
+
respond_with_resource_error
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def update
|
153
|
+
authorize! :update, @resource_class
|
154
|
+
@resource ||= @resource_class.find(params[:id])
|
155
|
+
authorize! :update, @resource
|
156
|
+
|
157
|
+
second_authorize = false
|
158
|
+
ActiveRecord::Base.transaction do
|
159
|
+
@resource.assign_attributes(resource_params(@resource))
|
160
|
+
second_authorize = can?(action_name.to_sym, @resource)
|
161
|
+
unless second_authorize
|
162
|
+
# NOTE: Does not halt the controller process, just rolls back the DB
|
163
|
+
raise ActiveRecord::Rollback
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
unless second_authorize
|
168
|
+
raise CanCan::AccessDenied.new("Not authorized!", action_name.to_sym, @resource)
|
169
|
+
end
|
170
|
+
|
171
|
+
# 2nd auth, on the updates of the object, without saving, so we can rollback without auth.
|
172
|
+
# authorize! :update, @resource
|
173
|
+
if @resource.save
|
174
|
+
respond_with_resource
|
175
|
+
else
|
176
|
+
begin
|
177
|
+
Rails.logger.warn "Failed object validations: could not update #{@resource_class}, id: #{@resource.id}: #{@resource.errors.full_messages}"
|
178
|
+
respond_with_resource_error
|
179
|
+
rescue Exception => e
|
180
|
+
Rails.logger.error "CanCanCanResourceController - Caught Internal Server Error: " + e.class.to_s + ': ' + e.message
|
181
|
+
Rails.logger.error Rails.backtrace_cleaner.clean(e.backtrace).join("\n").to_s
|
182
|
+
respond_with_resource_error
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def destroy
|
188
|
+
authorize! :destroy, @resource_class
|
189
|
+
@resource ||= @resource_class.find(params[:id])
|
190
|
+
authorize! :destroy, @resource
|
191
|
+
# retuning the resource in a pre-destroyed state as a destroy response
|
192
|
+
results = @resource
|
193
|
+
if @resource.destroy
|
194
|
+
respond_after_destroy
|
195
|
+
else
|
196
|
+
begin
|
197
|
+
Rails.logger.warn "Failed object validations: could not destroy #{@resource_class}, id: #{@resource.id}: #{@resource.errors.full_messages}"
|
198
|
+
respond_with_resource_invalid
|
199
|
+
rescue Exception => e
|
200
|
+
Rails.logger.error "CanCanCanResourceController - Caught Internal Server Error: " + e.class.to_s + ': ' + e.message
|
201
|
+
Rails.logger.error Rails.backtrace_cleaner.clean(e.backtrace).join("\n").to_s
|
202
|
+
respond_with_resource_error
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
protected
|
208
|
+
|
209
|
+
def respond_with_resources
|
210
|
+
respond_to do |format|
|
211
|
+
format.html # Renders the default
|
212
|
+
format.json { render json: @resources }
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def respond_with_resource
|
217
|
+
respond_to do |format|
|
218
|
+
format.html # Renders the default
|
219
|
+
format.json { render json: @resource }
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def respond_with_resource_invalid
|
224
|
+
respond_to do |format|
|
225
|
+
format.html # Renders the default
|
226
|
+
format.json { render json: @resource.errors.full_messages, status: 422 }
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def respond_with_resource_error
|
231
|
+
respond_to do |format|
|
232
|
+
format.html # Renders the default
|
233
|
+
format.json { render json: ["An error has occured. Our support teams have been notified and are working on a solution."], status: 422 }
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def respond_after_destroy
|
238
|
+
respond_to do |format|
|
239
|
+
format.html { redirect_to url_for(controller: controller_name, action: 'index') }
|
240
|
+
format.json { render json: results, status: :no_content }
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# meant to be overridden by inheriting controllers.
|
245
|
+
def index_resource_query resource_query
|
246
|
+
return resource_query
|
247
|
+
end
|
248
|
+
|
249
|
+
# can pass in custom method to supplant 'param.permit', like if you wanted to whitelist a hash instead of params.
|
250
|
+
# ex: CanCanCanResourceController#deactivate_helper, permits on fake params: ActionController::Parameters.new(deactive_params)
|
251
|
+
def resource_params resource_object = nil, opts = {}, &block
|
252
|
+
local_action_name = opts[:custom_action_name] || action_name
|
253
|
+
allowlist_permitted = get_nested_attributes_for_class(@resource_class, local_action_name.to_sym, resource_object)
|
254
|
+
|
255
|
+
# # Rails kludge, issue with allowing parameters with empty arrays
|
256
|
+
# # Needs to be nested, recursive
|
257
|
+
# # Updating params in-place
|
258
|
+
# params.each do |key, value|
|
259
|
+
# if key.to_s =~ /(.*)_ids/ && (value == "remove" || value == ["remove"])
|
260
|
+
# params[key] = []
|
261
|
+
# end
|
262
|
+
# end
|
263
|
+
|
264
|
+
if block_given?
|
265
|
+
params_with_only_allowed_parameters = yield(allowlist_permitted)
|
266
|
+
else
|
267
|
+
params_with_only_allowed_parameters = param_permit(allowlist_permitted)
|
268
|
+
end
|
269
|
+
|
270
|
+
# sanitize all input.
|
271
|
+
sanitized_params_with_only_allowed_parameters = clean_parameter_data(params_with_only_allowed_parameters)
|
272
|
+
|
273
|
+
# recast type (and have to re-permit)
|
274
|
+
sanitized_params_with_only_allowed_parameters = ActionController::Parameters.new(sanitized_params_with_only_allowed_parameters).permit(allowlist_permitted)
|
275
|
+
|
276
|
+
return sanitized_params_with_only_allowed_parameters
|
277
|
+
end
|
278
|
+
|
279
|
+
# recursive
|
280
|
+
# src: https://apidock.com/rails/v5.2.3/ActionView/Helpers/SanitizeHelper/sanitize
|
281
|
+
def clean_parameter_data param_value
|
282
|
+
# was an array element, and not an object.
|
283
|
+
# Check for HTML tags
|
284
|
+
if param_value.is_a?(String) && !(param_value =~ REGEX_FOR_HTML_TAG_DETECTION).nil?
|
285
|
+
# We need a better way, in the future, to specify the allowed values down to the Class and Column level.
|
286
|
+
return ActionController::Base.helpers.sanitize(param_value, {tags: self.class::DEFAULT_PARAMETER_SANITIZER_ALLOWED_TAGS, attributes: self.class::DEFAULT_PARAMETER_SANITIZER_ALLOWED_ATTRIBS})
|
287
|
+
elsif param_value.is_a?(String) || param_value.is_a?(Integer) || param_value.is_a?(Float) || param_value.nil? || [true, false].include?(param_value)
|
288
|
+
return param_value
|
289
|
+
end
|
290
|
+
|
291
|
+
if param_value.is_a?(Hash) || param_value.is_a?(Array) || param_value.is_a?(ActionController::Parameters)
|
292
|
+
# good to continue
|
293
|
+
else
|
294
|
+
error_msg = "Internal Server Error! Unsupported parameter type: #{param_value} (#{param_value.class})"
|
295
|
+
Rails.logger.error(error_msg)
|
296
|
+
raise error_msg
|
297
|
+
end
|
298
|
+
|
299
|
+
if param_value.is_a?(Array)
|
300
|
+
new_array = []
|
301
|
+
param_value.each do |array_element|
|
302
|
+
new_array << clean_parameter_data(array_element)
|
303
|
+
end
|
304
|
+
return new_array
|
305
|
+
else
|
306
|
+
new_hash = {}
|
307
|
+
keys = param_value.keys
|
308
|
+
keys.each do |key|
|
309
|
+
new_hash[key.to_sym] = clean_parameter_data(param_value[key])
|
310
|
+
end
|
311
|
+
return new_hash
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
# Not checking instances of classes. What if they are object-state dependent?
|
316
|
+
# Need to run them again, after object instantiation, but in a different method.
|
317
|
+
def get_nested_attributes_for_class resource_class, action_name, root_level_object, depth = 0
|
318
|
+
raise "invalid action class: #{action_name.class}" if !action_name.is_a?(Symbol)
|
319
|
+
association_parameters = []
|
320
|
+
if depth > MAX_ASSOCIATIVE_NESTED_DEPTH
|
321
|
+
return association_parameters
|
322
|
+
end
|
323
|
+
|
324
|
+
# Handle resource_class attribs
|
325
|
+
# issue here is the 'action_name' on the root 'resource_class' may not be the action that the user has for the 'assoc_class'
|
326
|
+
# i.e:
|
327
|
+
# We may want the user to update Account, and create attachments on it, but not 'update' attachments.
|
328
|
+
if depth == 0
|
329
|
+
association_parameters = current_ability.permitted_attributes(action_name, (root_level_object || resource_class))
|
330
|
+
else
|
331
|
+
association_parameters = current_ability.permitted_attributes(action_name, resource_class)
|
332
|
+
end
|
333
|
+
|
334
|
+
if resource_class.const_defined?('RESOURCE_CONTROLLER_ATTRIB_ALLOWLIST') && !resource_class::RESOURCE_CONTROLLER_ATTRIB_ALLOWLIST.nil?
|
335
|
+
association_parameters &= resource_class::RESOURCE_CONTROLLER_ATTRIB_ALLOWLIST
|
336
|
+
end
|
337
|
+
|
338
|
+
# remove customized, non-params, assoc' attrib data by only allowing class columns
|
339
|
+
association_parameters &= resource_class.column_names.collect(&:to_sym)
|
340
|
+
|
341
|
+
resource_class.reflect_on_all_associations(:has_many).each do |assoc_class|
|
342
|
+
resource_key = assoc_class.name
|
343
|
+
# attrib_permission_key = (resource_key.to_s.singularize + '_ids').to_sym
|
344
|
+
attrib_permission_key = IDS_ATTIB_PERMISSION_KEY_GEN.call(resource_key)
|
345
|
+
# action_permission_key = ('_can_add_or_remove_association_' + resource_key.to_s).to_sym
|
346
|
+
action_permission_key = IDS_ACTION_PERMISSION_KEY_GEN.call(resource_key)
|
347
|
+
# i.e. can?(:can_participation_ids, Account)
|
348
|
+
# Check to see if we manually gave the user a custom permission
|
349
|
+
# # (i.e.: can [:update, :can_account_sector_ids], Account)
|
350
|
+
# OR
|
351
|
+
# see if it has the attribute on the class's allowed params
|
352
|
+
if can?(action_permission_key, resource_class) || can?(action_name, resource_class, attrib_permission_key)
|
353
|
+
association_parameters << {
|
354
|
+
attrib_permission_key => []
|
355
|
+
}
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
resource_class.nested_attributes_options.each do |resource_key, options|
|
360
|
+
reflection_class = resource_class.reflect_on_association(resource_key).class
|
361
|
+
reflection_type = reflection_class.name
|
362
|
+
assoc_class = resource_class.reflect_on_association(resource_key).klass
|
363
|
+
|
364
|
+
if [
|
365
|
+
"ActiveRecord::Reflection::BelongsToReflection",
|
366
|
+
"ActiveRecord::Reflection::HasOneReflection",
|
367
|
+
"ActiveRecord::Reflection::HasManyReflection"
|
368
|
+
].include?(reflection_type)
|
369
|
+
parameter_key = NESTED_ATTIB_PERMISSION_KEY_GEN.call(resource_key)
|
370
|
+
permission_key = NESTED_ACTION_PERMISSION_KEY_GEN.call(resource_key)
|
371
|
+
|
372
|
+
# Can check if permission to update assoc is defined as an action OR as an attrib on the parent resource_class
|
373
|
+
if can?(permission_key, resource_class) || can?(action_name, resource_class, parameter_key)
|
374
|
+
# Handle recursion
|
375
|
+
assoc_parameters = get_nested_attributes_for_class(assoc_class, action_name, root_level_object, depth + 1)
|
376
|
+
|
377
|
+
if options[:allow_destroy] && can?(:destroy, resource_class)
|
378
|
+
assoc_parameters << :_destroy
|
379
|
+
end
|
380
|
+
|
381
|
+
association_parameters << {
|
382
|
+
parameter_key => assoc_parameters
|
383
|
+
}
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
return association_parameters
|
389
|
+
end
|
390
|
+
|
391
|
+
def param_permit base_parameters
|
392
|
+
params.permit(base_parameters)
|
393
|
+
end
|
394
|
+
|
395
|
+
def initialize_resource_class
|
396
|
+
# First priority is the namespaced model, e.g. User::Group
|
397
|
+
@resource_class ||= begin
|
398
|
+
namespaced_class = self.class.name.sub(/Controller$/, '').singularize
|
399
|
+
namespaced_class.constantize
|
400
|
+
rescue NameError
|
401
|
+
nil
|
402
|
+
end
|
403
|
+
|
404
|
+
# Second priority is the top namespace model, e.g. EngineName::Article for EngineName::Admin::ArticlesController
|
405
|
+
@resource_class ||= begin
|
406
|
+
namespaced_classes = self.class.name.sub(/Controller$/, '').split('::')
|
407
|
+
namespaced_class = [namespaced_classes.first, namespaced_classes.last].join('::').singularize
|
408
|
+
namespaced_class.constantize
|
409
|
+
rescue NameError
|
410
|
+
nil
|
411
|
+
end
|
412
|
+
|
413
|
+
# Third priority the camelcased c, i.e. UserGroup
|
414
|
+
@resource_class ||= begin
|
415
|
+
camelcased_class = self.class.name.sub(/Controller$/, '').gsub('::', '').singularize
|
416
|
+
camelcased_class.constantize
|
417
|
+
rescue NameError
|
418
|
+
nil
|
419
|
+
end
|
420
|
+
|
421
|
+
# Otherwise use the Group class, or fail
|
422
|
+
@resource_class ||= begin
|
423
|
+
class_name = self.controller_name.classify
|
424
|
+
class_name.constantize
|
425
|
+
rescue NameError => e
|
426
|
+
raise unless e.message.include?(class_name)
|
427
|
+
nil
|
428
|
+
end
|
429
|
+
# portal/portal_imports case needed this
|
430
|
+
@resource_class ||= begin
|
431
|
+
class_name = controller_path.classify
|
432
|
+
class_name.camelize.singularize.constantize
|
433
|
+
rescue NameError => e
|
434
|
+
raise unless e.message.include?(class_name)
|
435
|
+
nil
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
end
|
440
|
+
end
|
metadata
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cancancan_resource_controller
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- benjamin.dana.software.dev@gmail.com
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-07-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: cancancan
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 3.5.0
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 3.5.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.5.0
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 3.5.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: rails
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - '='
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 6.1.7.3
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - '='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 6.1.7.3
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '3.9'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '3.9'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: listen
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '3.2'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '3.2'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: rspec-rails
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '4.0'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '4.0'
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: database_cleaner
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '1.8'
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '1.8'
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: sqlite3
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '1.4'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - "~>"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '1.4'
|
117
|
+
description:
|
118
|
+
email:
|
119
|
+
executables: []
|
120
|
+
extensions: []
|
121
|
+
extra_rdoc_files: []
|
122
|
+
files:
|
123
|
+
- lib/cancancan/abstract_resource_controller.rb
|
124
|
+
- lib/cancancan_resource_controller.rb
|
125
|
+
homepage: https://github.com/danabr75/cancancan_resource_controller
|
126
|
+
licenses:
|
127
|
+
- LGPL-3.0-only
|
128
|
+
metadata: {}
|
129
|
+
post_install_message:
|
130
|
+
rdoc_options: []
|
131
|
+
require_paths:
|
132
|
+
- lib
|
133
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '2.4'
|
138
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
143
|
+
requirements: []
|
144
|
+
rubygems_version: 3.3.7
|
145
|
+
signing_key:
|
146
|
+
specification_version: 4
|
147
|
+
summary: A Rails Controller Module that uses CanCan's permitted attribs instead of
|
148
|
+
typical parameter allowlisting.
|
149
|
+
test_files: []
|