neo4j_legacy 7.2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1357 -0
  3. data/CONTRIBUTORS +8 -0
  4. data/Gemfile +38 -0
  5. data/README.md +103 -0
  6. data/bin/neo4j-jars +33 -0
  7. data/bin/rake +17 -0
  8. data/config/locales/en.yml +5 -0
  9. data/config/neo4j/add_classnames.yml +1 -0
  10. data/config/neo4j/config.yml +35 -0
  11. data/lib/active_support/per_thread_registry.rb +1 -0
  12. data/lib/backports/action_controller/metal/strong_parameters.rb +672 -0
  13. data/lib/backports/active_model/forbidden_attributes_protection.rb +30 -0
  14. data/lib/backports/active_support/concern.rb +13 -0
  15. data/lib/backports/active_support/core_ext/module/attribute_accessors.rb +10 -0
  16. data/lib/backports/active_support/logger.rb +99 -0
  17. data/lib/backports/active_support/logger_silence.rb +27 -0
  18. data/lib/backports/active_support/logger_thread_safe_level.rb +32 -0
  19. data/lib/backports/active_support/per_thread_registry.rb +60 -0
  20. data/lib/backports.rb +4 -0
  21. data/lib/neo4j/active_node/callbacks.rb +8 -0
  22. data/lib/neo4j/active_node/dependent/association_methods.rb +48 -0
  23. data/lib/neo4j/active_node/dependent/query_proxy_methods.rb +50 -0
  24. data/lib/neo4j/active_node/dependent.rb +11 -0
  25. data/lib/neo4j/active_node/enum.rb +29 -0
  26. data/lib/neo4j/active_node/has_n/association/rel_factory.rb +61 -0
  27. data/lib/neo4j/active_node/has_n/association/rel_wrapper.rb +23 -0
  28. data/lib/neo4j/active_node/has_n/association.rb +280 -0
  29. data/lib/neo4j/active_node/has_n/association_cypher_methods.rb +108 -0
  30. data/lib/neo4j/active_node/has_n.rb +532 -0
  31. data/lib/neo4j/active_node/id_property/accessor.rb +62 -0
  32. data/lib/neo4j/active_node/id_property.rb +187 -0
  33. data/lib/neo4j/active_node/initialize.rb +21 -0
  34. data/lib/neo4j/active_node/labels/index.rb +87 -0
  35. data/lib/neo4j/active_node/labels/reloading.rb +21 -0
  36. data/lib/neo4j/active_node/labels.rb +198 -0
  37. data/lib/neo4j/active_node/node_wrapper.rb +52 -0
  38. data/lib/neo4j/active_node/orm_adapter.rb +82 -0
  39. data/lib/neo4j/active_node/persistence.rb +175 -0
  40. data/lib/neo4j/active_node/property.rb +60 -0
  41. data/lib/neo4j/active_node/query/query_proxy.rb +361 -0
  42. data/lib/neo4j/active_node/query/query_proxy_eager_loading.rb +61 -0
  43. data/lib/neo4j/active_node/query/query_proxy_enumerable.rb +90 -0
  44. data/lib/neo4j/active_node/query/query_proxy_find_in_batches.rb +19 -0
  45. data/lib/neo4j/active_node/query/query_proxy_link.rb +117 -0
  46. data/lib/neo4j/active_node/query/query_proxy_methods.rb +210 -0
  47. data/lib/neo4j/active_node/query/query_proxy_methods_of_mass_updating.rb +83 -0
  48. data/lib/neo4j/active_node/query.rb +76 -0
  49. data/lib/neo4j/active_node/query_methods.rb +65 -0
  50. data/lib/neo4j/active_node/reflection.rb +86 -0
  51. data/lib/neo4j/active_node/rels.rb +11 -0
  52. data/lib/neo4j/active_node/scope.rb +146 -0
  53. data/lib/neo4j/active_node/unpersisted.rb +48 -0
  54. data/lib/neo4j/active_node/validations.rb +59 -0
  55. data/lib/neo4j/active_node.rb +105 -0
  56. data/lib/neo4j/active_rel/callbacks.rb +15 -0
  57. data/lib/neo4j/active_rel/initialize.rb +28 -0
  58. data/lib/neo4j/active_rel/persistence/query_factory.rb +95 -0
  59. data/lib/neo4j/active_rel/persistence.rb +114 -0
  60. data/lib/neo4j/active_rel/property.rb +95 -0
  61. data/lib/neo4j/active_rel/query.rb +95 -0
  62. data/lib/neo4j/active_rel/rel_wrapper.rb +22 -0
  63. data/lib/neo4j/active_rel/related_node.rb +83 -0
  64. data/lib/neo4j/active_rel/types.rb +82 -0
  65. data/lib/neo4j/active_rel/validations.rb +8 -0
  66. data/lib/neo4j/active_rel.rb +67 -0
  67. data/lib/neo4j/class_arguments.rb +39 -0
  68. data/lib/neo4j/config.rb +124 -0
  69. data/lib/neo4j/core/query.rb +22 -0
  70. data/lib/neo4j/errors.rb +28 -0
  71. data/lib/neo4j/migration.rb +127 -0
  72. data/lib/neo4j/paginated.rb +27 -0
  73. data/lib/neo4j/railtie.rb +169 -0
  74. data/lib/neo4j/schema/operation.rb +91 -0
  75. data/lib/neo4j/shared/attributes.rb +220 -0
  76. data/lib/neo4j/shared/callbacks.rb +64 -0
  77. data/lib/neo4j/shared/cypher.rb +37 -0
  78. data/lib/neo4j/shared/declared_properties.rb +204 -0
  79. data/lib/neo4j/shared/declared_property/index.rb +37 -0
  80. data/lib/neo4j/shared/declared_property.rb +118 -0
  81. data/lib/neo4j/shared/enum.rb +148 -0
  82. data/lib/neo4j/shared/filtered_hash.rb +79 -0
  83. data/lib/neo4j/shared/identity.rb +28 -0
  84. data/lib/neo4j/shared/initialize.rb +28 -0
  85. data/lib/neo4j/shared/marshal.rb +23 -0
  86. data/lib/neo4j/shared/mass_assignment.rb +58 -0
  87. data/lib/neo4j/shared/permitted_attributes.rb +28 -0
  88. data/lib/neo4j/shared/persistence.rb +231 -0
  89. data/lib/neo4j/shared/property.rb +220 -0
  90. data/lib/neo4j/shared/query_factory.rb +101 -0
  91. data/lib/neo4j/shared/rel_type_converters.rb +43 -0
  92. data/lib/neo4j/shared/serialized_properties.rb +30 -0
  93. data/lib/neo4j/shared/type_converters.rb +418 -0
  94. data/lib/neo4j/shared/typecasted_attributes.rb +98 -0
  95. data/lib/neo4j/shared/typecaster.rb +53 -0
  96. data/lib/neo4j/shared/validations.rb +48 -0
  97. data/lib/neo4j/shared.rb +51 -0
  98. data/lib/neo4j/tasks/migration.rake +24 -0
  99. data/lib/neo4j/timestamps/created.rb +9 -0
  100. data/lib/neo4j/timestamps/updated.rb +9 -0
  101. data/lib/neo4j/timestamps.rb +11 -0
  102. data/lib/neo4j/type_converters.rb +7 -0
  103. data/lib/neo4j/version.rb +3 -0
  104. data/lib/neo4j/wrapper.rb +4 -0
  105. data/lib/neo4j.rb +96 -0
  106. data/lib/rails/generators/neo4j/model/model_generator.rb +86 -0
  107. data/lib/rails/generators/neo4j/model/templates/model.erb +15 -0
  108. data/lib/rails/generators/neo4j_generator.rb +67 -0
  109. data/neo4j.gemspec +43 -0
  110. metadata +389 -0
@@ -0,0 +1,672 @@
1
+ unless defined? ActionController::Parameters
2
+ require 'rack/test'
3
+ require 'active_support/core_ext/hash/indifferent_access'
4
+ require 'active_support/core_ext/array/wrap'
5
+ require 'active_support/core_ext/string/filters'
6
+ require 'active_support/deprecation'
7
+ require 'active_support/rescuable'
8
+ require 'action_dispatch/http/upload'
9
+ require 'stringio'
10
+ require 'set'
11
+
12
+ module ActionController
13
+ # Raised when a required parameter is missing.
14
+ #
15
+ # params = ActionController::Parameters.new(a: {})
16
+ # params.fetch(:b)
17
+ # # => ActionController::ParameterMissing: param not found: b
18
+ # params.require(:a)
19
+ # # => ActionController::ParameterMissing: param not found: a
20
+ class ParameterMissing < KeyError
21
+ attr_reader :param # :nodoc:
22
+
23
+ def initialize(param) # :nodoc:
24
+ @param = param
25
+ super("param is missing or the value is empty: #{param}")
26
+ end
27
+ end
28
+
29
+ # Raised when a supplied parameter is not expected and
30
+ # ActionController::Parameters.action_on_unpermitted_parameters
31
+ # is set to <tt>:raise</tt>.
32
+ #
33
+ # params = ActionController::Parameters.new(a: "123", b: "456")
34
+ # params.permit(:c)
35
+ # # => ActionController::UnpermittedParameters: found unpermitted parameters: a, b
36
+ class UnpermittedParameters < IndexError
37
+ attr_reader :params # :nodoc:
38
+
39
+ def initialize(params) # :nodoc:
40
+ @params = params
41
+ super("found unpermitted parameter#{'s' if params.size > 1 }: #{params.join(", ")}")
42
+ end
43
+ end
44
+
45
+ # == Action Controller \Parameters
46
+ #
47
+ # Allows to choose which attributes should be whitelisted for mass updating
48
+ # and thus prevent accidentally exposing that which shouldn't be exposed.
49
+ # Provides two methods for this purpose: #require and #permit. The former is
50
+ # used to mark parameters as required. The latter is used to set the parameter
51
+ # as permitted and limit which attributes should be allowed for mass updating.
52
+ #
53
+ # params = ActionController::Parameters.new({
54
+ # person: {
55
+ # name: 'Francesco',
56
+ # age: 22,
57
+ # role: 'admin'
58
+ # }
59
+ # })
60
+ #
61
+ # permitted = params.require(:person).permit(:name, :age)
62
+ # permitted # => {"name"=>"Francesco", "age"=>22}
63
+ # permitted.class # => ActionController::Parameters
64
+ # permitted.permitted? # => true
65
+ #
66
+ # Person.first.update!(permitted)
67
+ # # => #<Person id: 1, name: "Francesco", age: 22, role: "user">
68
+ #
69
+ # It provides two options that controls the top-level behavior of new instances:
70
+ #
71
+ # * +permit_all_parameters+ - If it's +true+, all the parameters will be
72
+ # permitted by default. The default is +false+.
73
+ # * +action_on_unpermitted_parameters+ - Allow to control the behavior when parameters
74
+ # that are not explicitly permitted are found. The values can be <tt>:log</tt> to
75
+ # write a message on the logger or <tt>:raise</tt> to raise
76
+ # ActionController::UnpermittedParameters exception. The default value is <tt>:log</tt>
77
+ # in test and development environments, +false+ otherwise.
78
+ #
79
+ # Examples:
80
+ #
81
+ # params = ActionController::Parameters.new
82
+ # params.permitted? # => false
83
+ #
84
+ # ActionController::Parameters.permit_all_parameters = true
85
+ #
86
+ # params = ActionController::Parameters.new
87
+ # params.permitted? # => true
88
+ #
89
+ # params = ActionController::Parameters.new(a: "123", b: "456")
90
+ # params.permit(:c)
91
+ # # => {}
92
+ #
93
+ # ActionController::Parameters.action_on_unpermitted_parameters = :raise
94
+ #
95
+ # params = ActionController::Parameters.new(a: "123", b: "456")
96
+ # params.permit(:c)
97
+ # # => ActionController::UnpermittedParameters: found unpermitted keys: a, b
98
+ #
99
+ # Please note that these options *are not thread-safe*. In a multi-threaded
100
+ # environment they should only be set once at boot-time and never mutated at
101
+ # runtime.
102
+ #
103
+ # <tt>ActionController::Parameters</tt> inherits from
104
+ # <tt>ActiveSupport::HashWithIndifferentAccess</tt>, this means
105
+ # that you can fetch values using either <tt>:key</tt> or <tt>"key"</tt>.
106
+ #
107
+ # params = ActionController::Parameters.new(key: 'value')
108
+ # params[:key] # => "value"
109
+ # params["key"] # => "value"
110
+ class Parameters < ActiveSupport::HashWithIndifferentAccess
111
+ cattr_accessor :permit_all_parameters, instance_accessor: false
112
+ cattr_accessor :action_on_unpermitted_parameters, instance_accessor: false
113
+
114
+ # By default, never raise an UnpermittedParameters exception if these
115
+ # params are present. The default includes both 'controller' and 'action'
116
+ # because they are added by Rails and should be of no concern. One way
117
+ # to change these is to specify `always_permitted_parameters` in your
118
+ # config. For instance:
119
+ #
120
+ # config.always_permitted_parameters = %w( controller action format )
121
+ cattr_accessor :always_permitted_parameters
122
+ self.always_permitted_parameters = %w( controller action )
123
+
124
+ def self.const_missing(const_name)
125
+ super unless const_name == :NEVER_UNPERMITTED_PARAMS
126
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
127
+ `ActionController::Parameters::NEVER_UNPERMITTED_PARAMS` has been deprecated.
128
+ Use `ActionController::Parameters.always_permitted_parameters` instead.
129
+ MSG
130
+
131
+ always_permitted_parameters
132
+ end
133
+
134
+ # Returns a new instance of <tt>ActionController::Parameters</tt>.
135
+ # Also, sets the +permitted+ attribute to the default value of
136
+ # <tt>ActionController::Parameters.permit_all_parameters</tt>.
137
+ #
138
+ # class Person < ActiveRecord::Base
139
+ # end
140
+ #
141
+ # params = ActionController::Parameters.new(name: 'Francesco')
142
+ # params.permitted? # => false
143
+ # Person.new(params) # => ActiveModel::ForbiddenAttributesError
144
+ #
145
+ # ActionController::Parameters.permit_all_parameters = true
146
+ #
147
+ # params = ActionController::Parameters.new(name: 'Francesco')
148
+ # params.permitted? # => true
149
+ # Person.new(params) # => #<Person id: nil, name: "Francesco">
150
+ def initialize(attributes = nil)
151
+ super(attributes)
152
+ @permitted = self.class.permit_all_parameters
153
+ end
154
+
155
+ # Returns a safe +Hash+ representation of this parameter with all
156
+ # unpermitted keys removed.
157
+ #
158
+ # params = ActionController::Parameters.new({
159
+ # name: 'Senjougahara Hitagi',
160
+ # oddity: 'Heavy stone crab'
161
+ # })
162
+ # params.to_h # => {}
163
+ #
164
+ # safe_params = params.permit(:name)
165
+ # safe_params.to_h # => {"name"=>"Senjougahara Hitagi"}
166
+ def to_h
167
+ if permitted?
168
+ to_hash
169
+ else
170
+ slice(*self.class.always_permitted_parameters).permit!.to_h
171
+ end
172
+ end
173
+
174
+ # Returns an unsafe, unfiltered +Hash+ representation of this parameter.
175
+ def to_unsafe_h
176
+ to_hash
177
+ end
178
+ alias_method :to_unsafe_hash, :to_unsafe_h
179
+
180
+ # Convert all hashes in values into parameters, then yield each pair like
181
+ # the same way as <tt>Hash#each_pair</tt>
182
+ def each_pair(&block)
183
+ super do |key, value|
184
+ convert_hashes_to_parameters(key, value)
185
+ end
186
+
187
+ super
188
+ end
189
+
190
+ alias_method :each, :each_pair
191
+
192
+ # Attribute that keeps track of converted arrays, if any, to avoid double
193
+ # looping in the common use case permit + mass-assignment. Defined in a
194
+ # method to instantiate it only if needed.
195
+ #
196
+ # Testing membership still loops, but it's going to be faster than our own
197
+ # loop that converts values. Also, we are not going to build a new array
198
+ # object per fetch.
199
+ def converted_arrays
200
+ @converted_arrays ||= Set.new
201
+ end
202
+
203
+ # Returns +true+ if the parameter is permitted, +false+ otherwise.
204
+ #
205
+ # params = ActionController::Parameters.new
206
+ # params.permitted? # => false
207
+ # params.permit!
208
+ # params.permitted? # => true
209
+ def permitted?
210
+ @permitted
211
+ end
212
+
213
+ # Sets the +permitted+ attribute to +true+. This can be used to pass
214
+ # mass assignment. Returns +self+.
215
+ #
216
+ # class Person < ActiveRecord::Base
217
+ # end
218
+ #
219
+ # params = ActionController::Parameters.new(name: 'Francesco')
220
+ # params.permitted? # => false
221
+ # Person.new(params) # => ActiveModel::ForbiddenAttributesError
222
+ # params.permit!
223
+ # params.permitted? # => true
224
+ # Person.new(params) # => #<Person id: nil, name: "Francesco">
225
+ def permit!
226
+ each_pair do |key, value|
227
+ Array.wrap(value).each do |v|
228
+ v.permit! if v.respond_to? :permit!
229
+ end
230
+ end
231
+
232
+ @permitted = true
233
+ self
234
+ end
235
+
236
+ # Ensures that a parameter is present. If it's present, returns
237
+ # the parameter at the given +key+, otherwise raises an
238
+ # <tt>ActionController::ParameterMissing</tt> error.
239
+ #
240
+ # ActionController::Parameters.new(person: { name: 'Francesco' }).require(:person)
241
+ # # => {"name"=>"Francesco"}
242
+ #
243
+ # ActionController::Parameters.new(person: nil).require(:person)
244
+ # # => ActionController::ParameterMissing: param not found: person
245
+ #
246
+ # ActionController::Parameters.new(person: {}).require(:person)
247
+ # # => ActionController::ParameterMissing: param not found: person
248
+ def require(key)
249
+ value = self[key]
250
+ if value.present? || value == false
251
+ value
252
+ else
253
+ raise ParameterMissing.new(key)
254
+ end
255
+ end
256
+
257
+ # Alias of #require.
258
+ alias :required :require
259
+
260
+ # Returns a new <tt>ActionController::Parameters</tt> instance that
261
+ # includes only the given +filters+ and sets the +permitted+ attribute
262
+ # for the object to +true+. This is useful for limiting which attributes
263
+ # should be allowed for mass updating.
264
+ #
265
+ # params = ActionController::Parameters.new(user: { name: 'Francesco', age: 22, role: 'admin' })
266
+ # permitted = params.require(:user).permit(:name, :age)
267
+ # permitted.permitted? # => true
268
+ # permitted.has_key?(:name) # => true
269
+ # permitted.has_key?(:age) # => true
270
+ # permitted.has_key?(:role) # => false
271
+ #
272
+ # Only permitted scalars pass the filter. For example, given
273
+ #
274
+ # params.permit(:name)
275
+ #
276
+ # +:name+ passes it is a key of +params+ whose associated value is of type
277
+ # +String+, +Symbol+, +NilClass+, +Numeric+, +TrueClass+, +FalseClass+,
278
+ # +Date+, +Time+, +DateTime+, +StringIO+, +IO+,
279
+ # +ActionDispatch::Http::UploadedFile+ or +Rack::Test::UploadedFile+.
280
+ # Otherwise, the key +:name+ is filtered out.
281
+ #
282
+ # You may declare that the parameter should be an array of permitted scalars
283
+ # by mapping it to an empty array:
284
+ #
285
+ # params = ActionController::Parameters.new(tags: ['rails', 'parameters'])
286
+ # params.permit(tags: [])
287
+ #
288
+ # You can also use +permit+ on nested parameters, like:
289
+ #
290
+ # params = ActionController::Parameters.new({
291
+ # person: {
292
+ # name: 'Francesco',
293
+ # age: 22,
294
+ # pets: [{
295
+ # name: 'Purplish',
296
+ # category: 'dogs'
297
+ # }]
298
+ # }
299
+ # })
300
+ #
301
+ # permitted = params.permit(person: [ :name, { pets: :name } ])
302
+ # permitted.permitted? # => true
303
+ # permitted[:person][:name] # => "Francesco"
304
+ # permitted[:person][:age] # => nil
305
+ # permitted[:person][:pets][0][:name] # => "Purplish"
306
+ # permitted[:person][:pets][0][:category] # => nil
307
+ #
308
+ # Note that if you use +permit+ in a key that points to a hash,
309
+ # it won't allow all the hash. You also need to specify which
310
+ # attributes inside the hash should be whitelisted.
311
+ #
312
+ # params = ActionController::Parameters.new({
313
+ # person: {
314
+ # contact: {
315
+ # email: 'none@test.com',
316
+ # phone: '555-1234'
317
+ # }
318
+ # }
319
+ # })
320
+ #
321
+ # params.require(:person).permit(:contact)
322
+ # # => {}
323
+ #
324
+ # params.require(:person).permit(contact: :phone)
325
+ # # => {"contact"=>{"phone"=>"555-1234"}}
326
+ #
327
+ # params.require(:person).permit(contact: [ :email, :phone ])
328
+ # # => {"contact"=>{"email"=>"none@test.com", "phone"=>"555-1234"}}
329
+ def permit(*filters)
330
+ params = self.class.new
331
+
332
+ filters.flatten.each do |filter|
333
+ case filter
334
+ when Symbol, String
335
+ permitted_scalar_filter(params, filter)
336
+ when Hash then
337
+ hash_filter(params, filter)
338
+ end
339
+ end
340
+
341
+ unpermitted_parameters!(params) if self.class.action_on_unpermitted_parameters
342
+
343
+ params.permit!
344
+ end
345
+
346
+ # Returns a parameter for the given +key+. If not found,
347
+ # returns +nil+.
348
+ #
349
+ # params = ActionController::Parameters.new(person: { name: 'Francesco' })
350
+ # params[:person] # => {"name"=>"Francesco"}
351
+ # params[:none] # => nil
352
+ def [](key)
353
+ convert_hashes_to_parameters(key, super)
354
+ end
355
+
356
+ # Returns a parameter for the given +key+. If the +key+
357
+ # can't be found, there are several options: With no other arguments,
358
+ # it will raise an <tt>ActionController::ParameterMissing</tt> error;
359
+ # if more arguments are given, then that will be returned; if a block
360
+ # is given, then that will be run and its result returned.
361
+ #
362
+ # params = ActionController::Parameters.new(person: { name: 'Francesco' })
363
+ # params.fetch(:person) # => {"name"=>"Francesco"}
364
+ # params.fetch(:none) # => ActionController::ParameterMissing: param not found: none
365
+ # params.fetch(:none, 'Francesco') # => "Francesco"
366
+ # params.fetch(:none) { 'Francesco' } # => "Francesco"
367
+ def fetch(key, *args)
368
+ convert_hashes_to_parameters(key, super, false)
369
+ rescue KeyError
370
+ raise ActionController::ParameterMissing.new(key)
371
+ end
372
+
373
+ # Returns a new <tt>ActionController::Parameters</tt> instance that
374
+ # includes only the given +keys+. If the given +keys+
375
+ # don't exist, returns an empty hash.
376
+ #
377
+ # params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
378
+ # params.slice(:a, :b) # => {"a"=>1, "b"=>2}
379
+ # params.slice(:d) # => {}
380
+ def slice(*keys)
381
+ new_instance_with_inherited_permitted_status(super)
382
+ end
383
+
384
+ # Removes and returns the key/value pairs matching the given keys.
385
+ #
386
+ # params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
387
+ # params.extract!(:a, :b) # => {"a"=>1, "b"=>2}
388
+ # params # => {"c"=>3}
389
+ def extract!(*keys)
390
+ new_instance_with_inherited_permitted_status(super)
391
+ end
392
+
393
+ # Returns a new <tt>ActionController::Parameters</tt> with the results of
394
+ # running +block+ once for every value. The keys are unchanged.
395
+ #
396
+ # params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
397
+ # params.transform_values { |x| x * 2 }
398
+ # # => {"a"=>2, "b"=>4, "c"=>6}
399
+ def transform_values
400
+ if block_given?
401
+ new_instance_with_inherited_permitted_status(super)
402
+ else
403
+ super
404
+ end
405
+ end
406
+
407
+ # This method is here only to make sure that the returned object has the
408
+ # correct +permitted+ status. It should not matter since the parent of
409
+ # this object is +HashWithIndifferentAccess+
410
+ def transform_keys # :nodoc:
411
+ if block_given?
412
+ new_instance_with_inherited_permitted_status(super)
413
+ else
414
+ super
415
+ end
416
+ end
417
+
418
+ # Deletes and returns a key-value pair from +Parameters+ whose key is equal
419
+ # to key. If the key is not found, returns the default value. If the
420
+ # optional code block is given and the key is not found, pass in the key
421
+ # and return the result of block.
422
+ def delete(key, &block)
423
+ convert_hashes_to_parameters(key, super, false)
424
+ end
425
+
426
+ # Equivalent to Hash#keep_if, but returns nil if no changes were made.
427
+ def select!(&block)
428
+ convert_value_to_parameters(super)
429
+ end
430
+
431
+ # Returns an exact copy of the <tt>ActionController::Parameters</tt>
432
+ # instance. +permitted+ state is kept on the duped object.
433
+ #
434
+ # params = ActionController::Parameters.new(a: 1)
435
+ # params.permit!
436
+ # params.permitted? # => true
437
+ # copy_params = params.dup # => {"a"=>1}
438
+ # copy_params.permitted? # => true
439
+ def dup
440
+ super.tap do |duplicate|
441
+ duplicate.permitted = @permitted
442
+ end
443
+ end
444
+
445
+ protected
446
+ def permitted=(new_permitted)
447
+ @permitted = new_permitted
448
+ end
449
+
450
+ private
451
+ def new_instance_with_inherited_permitted_status(hash)
452
+ self.class.new(hash).tap do |new_instance|
453
+ new_instance.permitted = @permitted
454
+ end
455
+ end
456
+
457
+ def convert_hashes_to_parameters(key, value, assign_if_converted=true)
458
+ converted = convert_value_to_parameters(value)
459
+ self[key] = converted if assign_if_converted && !converted.equal?(value)
460
+ converted
461
+ end
462
+
463
+ def convert_value_to_parameters(value)
464
+ if value.is_a?(Array) && !converted_arrays.member?(value)
465
+ converted = value.map { |_| convert_value_to_parameters(_) }
466
+ converted_arrays << converted
467
+ converted
468
+ elsif value.is_a?(Parameters) || !value.is_a?(Hash)
469
+ value
470
+ else
471
+ self.class.new(value)
472
+ end
473
+ end
474
+
475
+ def each_element(object)
476
+ if object.is_a?(Array)
477
+ object.map { |el| yield el }.compact
478
+ elsif fields_for_style?(object)
479
+ hash = object.class.new
480
+ object.each { |k,v| hash[k] = yield v }
481
+ hash
482
+ else
483
+ yield object
484
+ end
485
+ end
486
+
487
+ def fields_for_style?(object)
488
+ object.is_a?(Hash) && object.all? { |k, v| k =~ /\A-?\d+\z/ && v.is_a?(Hash) }
489
+ end
490
+
491
+ def unpermitted_parameters!(params)
492
+ unpermitted_keys = unpermitted_keys(params)
493
+ if unpermitted_keys.any?
494
+ case self.class.action_on_unpermitted_parameters
495
+ when :log
496
+ name = "unpermitted_parameters.action_controller"
497
+ ActiveSupport::Notifications.instrument(name, keys: unpermitted_keys)
498
+ when :raise
499
+ raise ActionController::UnpermittedParameters.new(unpermitted_keys)
500
+ end
501
+ end
502
+ end
503
+
504
+ def unpermitted_keys(params)
505
+ self.keys - params.keys - self.always_permitted_parameters
506
+ end
507
+
508
+ #
509
+ # --- Filtering ----------------------------------------------------------
510
+ #
511
+
512
+ # This is a white list of permitted scalar types that includes the ones
513
+ # supported in XML and JSON requests.
514
+ #
515
+ # This list is in particular used to filter ordinary requests, String goes
516
+ # as first element to quickly short-circuit the common case.
517
+ #
518
+ # If you modify this collection please update the API of +permit+ above.
519
+ PERMITTED_SCALAR_TYPES = [
520
+ String,
521
+ Symbol,
522
+ NilClass,
523
+ Numeric,
524
+ TrueClass,
525
+ FalseClass,
526
+ Date,
527
+ Time,
528
+ # DateTimes are Dates, we document the type but avoid the redundant check.
529
+ StringIO,
530
+ IO,
531
+ ActionDispatch::Http::UploadedFile,
532
+ Rack::Test::UploadedFile,
533
+ ]
534
+
535
+ def permitted_scalar?(value)
536
+ PERMITTED_SCALAR_TYPES.any? {|type| value.is_a?(type)}
537
+ end
538
+
539
+ def permitted_scalar_filter(params, key)
540
+ if has_key?(key) && permitted_scalar?(self[key])
541
+ params[key] = self[key]
542
+ end
543
+
544
+ keys.grep(/\A#{Regexp.escape(key)}\(\d+[if]?\)\z/) do |k|
545
+ if permitted_scalar?(self[k])
546
+ params[k] = self[k]
547
+ end
548
+ end
549
+ end
550
+
551
+ def array_of_permitted_scalars?(value)
552
+ if value.is_a?(Array)
553
+ value.all? {|element| permitted_scalar?(element)}
554
+ end
555
+ end
556
+
557
+ def array_of_permitted_scalars_filter(params, key)
558
+ if has_key?(key) && array_of_permitted_scalars?(self[key])
559
+ params[key] = self[key]
560
+ end
561
+ end
562
+
563
+ EMPTY_ARRAY = []
564
+ def hash_filter(params, filter)
565
+ filter = filter.with_indifferent_access
566
+
567
+ # Slicing filters out non-declared keys.
568
+ slice(*filter.keys).each do |key, value|
569
+ next unless value
570
+
571
+ if filter[key] == EMPTY_ARRAY
572
+ # Declaration { comment_ids: [] }.
573
+ array_of_permitted_scalars_filter(params, key)
574
+ else
575
+ # Declaration { user: :name } or { user: [:name, :age, { address: ... }] }.
576
+ params[key] = each_element(value) do |element|
577
+ if element.is_a?(Hash)
578
+ element = self.class.new(element) unless element.respond_to?(:permit)
579
+ element.permit(*Array.wrap(filter[key]))
580
+ end
581
+ end
582
+ end
583
+ end
584
+ end
585
+ end
586
+
587
+ # == Strong \Parameters
588
+ #
589
+ # It provides an interface for protecting attributes from end-user
590
+ # assignment. This makes Action Controller parameters forbidden
591
+ # to be used in Active Model mass assignment until they have been
592
+ # whitelisted.
593
+ #
594
+ # In addition, parameters can be marked as required and flow through a
595
+ # predefined raise/rescue flow to end up as a 400 Bad Request with no
596
+ # effort.
597
+ #
598
+ # class PeopleController < ActionController::Base
599
+ # # Using "Person.create(params[:person])" would raise an
600
+ # # ActiveModel::ForbiddenAttributes exception because it'd
601
+ # # be using mass assignment without an explicit permit step.
602
+ # # This is the recommended form:
603
+ # def create
604
+ # Person.create(person_params)
605
+ # end
606
+ #
607
+ # # This will pass with flying colors as long as there's a person key in the
608
+ # # parameters, otherwise it'll raise an ActionController::MissingParameter
609
+ # # exception, which will get caught by ActionController::Base and turned
610
+ # # into a 400 Bad Request reply.
611
+ # def update
612
+ # redirect_to current_account.people.find(params[:id]).tap { |person|
613
+ # person.update!(person_params)
614
+ # }
615
+ # end
616
+ #
617
+ # private
618
+ # # Using a private method to encapsulate the permissible parameters is
619
+ # # just a good pattern since you'll be able to reuse the same permit
620
+ # # list between create and update. Also, you can specialize this method
621
+ # # with per-user checking of permissible attributes.
622
+ # def person_params
623
+ # params.require(:person).permit(:name, :age)
624
+ # end
625
+ # end
626
+ #
627
+ # In order to use <tt>accepts_nested_attributes_for</tt> with Strong \Parameters, you
628
+ # will need to specify which nested attributes should be whitelisted.
629
+ #
630
+ # class Person
631
+ # has_many :pets
632
+ # accepts_nested_attributes_for :pets
633
+ # end
634
+ #
635
+ # class PeopleController < ActionController::Base
636
+ # def create
637
+ # Person.create(person_params)
638
+ # end
639
+ #
640
+ # ...
641
+ #
642
+ # private
643
+ #
644
+ # def person_params
645
+ # # It's mandatory to specify the nested attributes that should be whitelisted.
646
+ # # If you use `permit` with just the key that points to the nested attributes hash,
647
+ # # it will return an empty hash.
648
+ # params.require(:person).permit(:name, :age, pets_attributes: [ :name, :category ])
649
+ # end
650
+ # end
651
+ #
652
+ # See ActionController::Parameters.require and ActionController::Parameters.permit
653
+ # for more information.
654
+ module StrongParameters
655
+ extend ActiveSupport::Concern
656
+ include ActiveSupport::Rescuable
657
+
658
+ # Returns a new ActionController::Parameters object that
659
+ # has been instantiated with the <tt>request.parameters</tt>.
660
+ def params
661
+ @_params ||= Parameters.new(request.parameters)
662
+ end
663
+
664
+ # Assigns the given +value+ to the +params+ hash. If +value+
665
+ # is a Hash, this will create an ActionController::Parameters
666
+ # object that has been instantiated with the given +value+ hash.
667
+ def params=(value)
668
+ @_params = value.is_a?(Hash) ? Parameters.new(value) : value
669
+ end
670
+ end
671
+ end
672
+ end
@@ -0,0 +1,30 @@
1
+ unless defined? ActiveModel::ForbiddenAttributesProtection
2
+ module ActiveModel
3
+ # Raised when forbidden attributes are used for mass assignment.
4
+ #
5
+ # class Person < ActiveRecord::Base
6
+ # end
7
+ #
8
+ # params = ActionController::Parameters.new(name: 'Bob')
9
+ # Person.new(params)
10
+ # # => ActiveModel::ForbiddenAttributesError
11
+ #
12
+ # params.permit!
13
+ # Person.new(params)
14
+ # # => #<Person id: nil, name: "Bob">
15
+ class ForbiddenAttributesError < StandardError
16
+ end
17
+
18
+ module ForbiddenAttributesProtection # :nodoc:
19
+ protected
20
+ def sanitize_for_mass_assignment(attributes)
21
+ if attributes.respond_to?(:permitted?) && !attributes.permitted?
22
+ raise ActiveModel::ForbiddenAttributesError
23
+ else
24
+ attributes
25
+ end
26
+ end
27
+ alias :sanitize_forbidden_attributes :sanitize_for_mass_assignment
28
+ end
29
+ end
30
+ end