-
Notifications
You must be signed in to change notification settings - Fork 21.6k
/
strong_parameters.rb
132 lines (108 loc) · 3.32 KB
/
strong_parameters.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
require 'active_support/concern'
require 'active_support/core_ext/hash/indifferent_access'
require 'active_support/rescuable'
module ActionController
# Raised when a required parameter is missing.
#
# params = ActionController::Parameters.new(a: {})
# params.fetch(:b)
# # => ActionController::ParameterMissing: key not found: b
# params.require(:a)
# # => ActionController::ParameterMissing: key not found: a
class ParameterMissing < KeyError
attr_reader :param # :nodoc:
def initialize(param) # :nodoc:
@param = param
super("key not found: #{param}")
end
end
class Parameters < ActiveSupport::HashWithIndifferentAccess
cattr_accessor :permit_all_parameters, instance_accessor: false
attr_accessor :permitted
alias :permitted? :permitted
def initialize(attributes = nil)
super(attributes)
@permitted = self.class.permit_all_parameters
end
def permit!
@permitted = true
self
end
def require(key)
self[key].presence || raise(ParameterMissing.new(key))
end
alias :required :require
def permit(*filters)
params = self.class.new
filters.each do |filter|
case filter
when Symbol, String then
params[filter] = self[filter] if has_key?(filter)
when Hash then
self.slice(*filter.keys).each do |key, values|
return unless values
key = key.to_sym
params[key] = each_element(values) do |value|
# filters are a Hash, so we expect value to be a Hash too
next if filter.is_a?(Hash) && !value.is_a?(Hash)
value = self.class.new(value) if !value.respond_to?(:permit)
value.permit(*Array.wrap(filter[key]))
end
end
end
end
params.permit!
end
def [](key)
convert_hashes_to_parameters(key, super)
end
def fetch(key, *args)
convert_hashes_to_parameters(key, super)
rescue KeyError
raise ActionController::ParameterMissing.new(key)
end
def slice(*keys)
self.class.new(super)
end
def dup
super.tap do |duplicate|
duplicate.instance_variable_set :@permitted, @permitted
end
end
private
def convert_hashes_to_parameters(key, value)
if value.is_a?(Parameters) || !value.is_a?(Hash)
value
else
# Convert to Parameters on first access
self[key] = self.class.new(value)
end
end
def each_element(object)
if object.is_a?(Array)
object.map { |el| yield el }.compact
elsif object.is_a?(Hash) && object.keys.all? { |k| k =~ /\A-?\d+\z/ }
hash = object.class.new
object.each { |k,v| hash[k] = yield v }
hash
else
yield object
end
end
end
module StrongParameters
extend ActiveSupport::Concern
include ActiveSupport::Rescuable
included do
rescue_from(ActionController::ParameterMissing) do |parameter_missing_exception|
render text: "Required parameter missing: #{parameter_missing_exception.param}", status: :bad_request
end
end
def params
@_params ||= Parameters.new(request.parameters)
end
def params=(val)
@_params = val.is_a?(Hash) ? Parameters.new(val) : val
end
end
end