neo4j_legacy 7.2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +1357 -0
- data/CONTRIBUTORS +8 -0
- data/Gemfile +38 -0
- data/README.md +103 -0
- data/bin/neo4j-jars +33 -0
- data/bin/rake +17 -0
- data/config/locales/en.yml +5 -0
- data/config/neo4j/add_classnames.yml +1 -0
- data/config/neo4j/config.yml +35 -0
- data/lib/active_support/per_thread_registry.rb +1 -0
- data/lib/backports/action_controller/metal/strong_parameters.rb +672 -0
- data/lib/backports/active_model/forbidden_attributes_protection.rb +30 -0
- data/lib/backports/active_support/concern.rb +13 -0
- data/lib/backports/active_support/core_ext/module/attribute_accessors.rb +10 -0
- data/lib/backports/active_support/logger.rb +99 -0
- data/lib/backports/active_support/logger_silence.rb +27 -0
- data/lib/backports/active_support/logger_thread_safe_level.rb +32 -0
- data/lib/backports/active_support/per_thread_registry.rb +60 -0
- data/lib/backports.rb +4 -0
- data/lib/neo4j/active_node/callbacks.rb +8 -0
- data/lib/neo4j/active_node/dependent/association_methods.rb +48 -0
- data/lib/neo4j/active_node/dependent/query_proxy_methods.rb +50 -0
- data/lib/neo4j/active_node/dependent.rb +11 -0
- data/lib/neo4j/active_node/enum.rb +29 -0
- data/lib/neo4j/active_node/has_n/association/rel_factory.rb +61 -0
- data/lib/neo4j/active_node/has_n/association/rel_wrapper.rb +23 -0
- data/lib/neo4j/active_node/has_n/association.rb +280 -0
- data/lib/neo4j/active_node/has_n/association_cypher_methods.rb +108 -0
- data/lib/neo4j/active_node/has_n.rb +532 -0
- data/lib/neo4j/active_node/id_property/accessor.rb +62 -0
- data/lib/neo4j/active_node/id_property.rb +187 -0
- data/lib/neo4j/active_node/initialize.rb +21 -0
- data/lib/neo4j/active_node/labels/index.rb +87 -0
- data/lib/neo4j/active_node/labels/reloading.rb +21 -0
- data/lib/neo4j/active_node/labels.rb +198 -0
- data/lib/neo4j/active_node/node_wrapper.rb +52 -0
- data/lib/neo4j/active_node/orm_adapter.rb +82 -0
- data/lib/neo4j/active_node/persistence.rb +175 -0
- data/lib/neo4j/active_node/property.rb +60 -0
- data/lib/neo4j/active_node/query/query_proxy.rb +361 -0
- data/lib/neo4j/active_node/query/query_proxy_eager_loading.rb +61 -0
- data/lib/neo4j/active_node/query/query_proxy_enumerable.rb +90 -0
- data/lib/neo4j/active_node/query/query_proxy_find_in_batches.rb +19 -0
- data/lib/neo4j/active_node/query/query_proxy_link.rb +117 -0
- data/lib/neo4j/active_node/query/query_proxy_methods.rb +210 -0
- data/lib/neo4j/active_node/query/query_proxy_methods_of_mass_updating.rb +83 -0
- data/lib/neo4j/active_node/query.rb +76 -0
- data/lib/neo4j/active_node/query_methods.rb +65 -0
- data/lib/neo4j/active_node/reflection.rb +86 -0
- data/lib/neo4j/active_node/rels.rb +11 -0
- data/lib/neo4j/active_node/scope.rb +146 -0
- data/lib/neo4j/active_node/unpersisted.rb +48 -0
- data/lib/neo4j/active_node/validations.rb +59 -0
- data/lib/neo4j/active_node.rb +105 -0
- data/lib/neo4j/active_rel/callbacks.rb +15 -0
- data/lib/neo4j/active_rel/initialize.rb +28 -0
- data/lib/neo4j/active_rel/persistence/query_factory.rb +95 -0
- data/lib/neo4j/active_rel/persistence.rb +114 -0
- data/lib/neo4j/active_rel/property.rb +95 -0
- data/lib/neo4j/active_rel/query.rb +95 -0
- data/lib/neo4j/active_rel/rel_wrapper.rb +22 -0
- data/lib/neo4j/active_rel/related_node.rb +83 -0
- data/lib/neo4j/active_rel/types.rb +82 -0
- data/lib/neo4j/active_rel/validations.rb +8 -0
- data/lib/neo4j/active_rel.rb +67 -0
- data/lib/neo4j/class_arguments.rb +39 -0
- data/lib/neo4j/config.rb +124 -0
- data/lib/neo4j/core/query.rb +22 -0
- data/lib/neo4j/errors.rb +28 -0
- data/lib/neo4j/migration.rb +127 -0
- data/lib/neo4j/paginated.rb +27 -0
- data/lib/neo4j/railtie.rb +169 -0
- data/lib/neo4j/schema/operation.rb +91 -0
- data/lib/neo4j/shared/attributes.rb +220 -0
- data/lib/neo4j/shared/callbacks.rb +64 -0
- data/lib/neo4j/shared/cypher.rb +37 -0
- data/lib/neo4j/shared/declared_properties.rb +204 -0
- data/lib/neo4j/shared/declared_property/index.rb +37 -0
- data/lib/neo4j/shared/declared_property.rb +118 -0
- data/lib/neo4j/shared/enum.rb +148 -0
- data/lib/neo4j/shared/filtered_hash.rb +79 -0
- data/lib/neo4j/shared/identity.rb +28 -0
- data/lib/neo4j/shared/initialize.rb +28 -0
- data/lib/neo4j/shared/marshal.rb +23 -0
- data/lib/neo4j/shared/mass_assignment.rb +58 -0
- data/lib/neo4j/shared/permitted_attributes.rb +28 -0
- data/lib/neo4j/shared/persistence.rb +231 -0
- data/lib/neo4j/shared/property.rb +220 -0
- data/lib/neo4j/shared/query_factory.rb +101 -0
- data/lib/neo4j/shared/rel_type_converters.rb +43 -0
- data/lib/neo4j/shared/serialized_properties.rb +30 -0
- data/lib/neo4j/shared/type_converters.rb +418 -0
- data/lib/neo4j/shared/typecasted_attributes.rb +98 -0
- data/lib/neo4j/shared/typecaster.rb +53 -0
- data/lib/neo4j/shared/validations.rb +48 -0
- data/lib/neo4j/shared.rb +51 -0
- data/lib/neo4j/tasks/migration.rake +24 -0
- data/lib/neo4j/timestamps/created.rb +9 -0
- data/lib/neo4j/timestamps/updated.rb +9 -0
- data/lib/neo4j/timestamps.rb +11 -0
- data/lib/neo4j/type_converters.rb +7 -0
- data/lib/neo4j/version.rb +3 -0
- data/lib/neo4j/wrapper.rb +4 -0
- data/lib/neo4j.rb +96 -0
- data/lib/rails/generators/neo4j/model/model_generator.rb +86 -0
- data/lib/rails/generators/neo4j/model/templates/model.erb +15 -0
- data/lib/rails/generators/neo4j_generator.rb +67 -0
- data/neo4j.gemspec +43 -0
- 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
|