durable_parameters 0.2.3
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +853 -0
- data/Rakefile +29 -0
- data/app/params/account_params.rb.example +38 -0
- data/app/params/application_params.rb +16 -0
- data/lib/durable_parameters/adapters/hanami.rb +138 -0
- data/lib/durable_parameters/adapters/rage.rb +124 -0
- data/lib/durable_parameters/adapters/rails.rb +280 -0
- data/lib/durable_parameters/adapters/sinatra.rb +91 -0
- data/lib/durable_parameters/core/application_params.rb +334 -0
- data/lib/durable_parameters/core/configuration.rb +83 -0
- data/lib/durable_parameters/core/forbidden_attributes_protection.rb +48 -0
- data/lib/durable_parameters/core/parameters.rb +643 -0
- data/lib/durable_parameters/core/params_registry.rb +110 -0
- data/lib/durable_parameters/core.rb +15 -0
- data/lib/durable_parameters/log_subscriber.rb +34 -0
- data/lib/durable_parameters/railtie.rb +65 -0
- data/lib/durable_parameters/version.rb +7 -0
- data/lib/durable_parameters.rb +41 -0
- data/lib/generators/rails/USAGE +12 -0
- data/lib/generators/rails/durable_parameters_controller_generator.rb +17 -0
- data/lib/generators/rails/templates/controller.rb +94 -0
- data/lib/legacy/action_controller/application_params.rb +235 -0
- data/lib/legacy/action_controller/parameters.rb +524 -0
- data/lib/legacy/action_controller/params_registry.rb +108 -0
- data/lib/legacy/active_model/forbidden_attributes_protection.rb +40 -0
- data/test/action_controller_required_params_test.rb +36 -0
- data/test/action_controller_tainted_params_test.rb +29 -0
- data/test/active_model_mass_assignment_taint_protection_test.rb +25 -0
- data/test/application_params_array_test.rb +245 -0
- data/test/application_params_edge_cases_test.rb +361 -0
- data/test/application_params_test.rb +893 -0
- data/test/controller_generator_test.rb +31 -0
- data/test/core_parameters_test.rb +2376 -0
- data/test/durable_parameters_test.rb +115 -0
- data/test/enhanced_error_messages_test.rb +120 -0
- data/test/gemfiles/Gemfile.rails-3.0.x +14 -0
- data/test/gemfiles/Gemfile.rails-3.1.x +14 -0
- data/test/gemfiles/Gemfile.rails-3.2.x +14 -0
- data/test/log_on_unpermitted_params_test.rb +49 -0
- data/test/metadata_validation_test.rb +294 -0
- data/test/multi_parameter_attributes_test.rb +38 -0
- data/test/parameters_core_methods_test.rb +503 -0
- data/test/parameters_integration_test.rb +553 -0
- data/test/parameters_permit_test.rb +491 -0
- data/test/parameters_require_test.rb +9 -0
- data/test/parameters_taint_test.rb +98 -0
- data/test/params_registry_concurrency_test.rb +422 -0
- data/test/params_registry_test.rb +112 -0
- data/test/permit_by_model_test.rb +227 -0
- data/test/raise_on_unpermitted_params_test.rb +32 -0
- data/test/test_helper.rb +38 -0
- data/test/transform_params_edge_cases_test.rb +526 -0
- data/test/transformation_test.rb +360 -0
- metadata +223 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
class PeopleController < ActionController::Base
|
|
4
|
+
def create
|
|
5
|
+
render plain: params[:person].permitted? ? "untainted" : "tainted"
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def create_with_permit
|
|
9
|
+
render plain: params[:person].permit(:name).permitted? ? "untainted" : "tainted"
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class ActionControllerTaintedParamsTest < ActionController::TestCase
|
|
14
|
+
tests PeopleController
|
|
15
|
+
|
|
16
|
+
setup do
|
|
17
|
+
@routes = Rails.application.routes
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_parameters_are_tainted
|
|
21
|
+
post :create, params: { :person => { :name => "Mjallo!" } }
|
|
22
|
+
assert_equal "tainted", response.body
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_parameters_can_be_permitted_and_are_then_not_tainted
|
|
26
|
+
post :create_with_permit, params: { :person => { :name => "Mjallo!" } }
|
|
27
|
+
assert_equal "untainted", response.body
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
class Person
|
|
4
|
+
include StrongParameters::Core::ForbiddenAttributesProtection
|
|
5
|
+
|
|
6
|
+
public :sanitize_for_mass_assignment
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
class ActiveModelMassUpdateProtectionTest < Minitest::Test
|
|
10
|
+
def test_forbidden_attributes_cannot_be_used_for_mass_updating
|
|
11
|
+
assert_raises(StrongParameters::Core::ForbiddenAttributes) do
|
|
12
|
+
Person.new.sanitize_for_mass_assignment(ActionController::Parameters.new(:a => "b"))
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_permitted_attributes_can_be_used_for_mass_updating
|
|
17
|
+
result = Person.new.sanitize_for_mass_assignment(ActionController::Parameters.new(:a => "b").permit(:a))
|
|
18
|
+
assert_equal({ "a" => "b" }, result.to_h)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_regular_attributes_should_still_be_allowed
|
|
22
|
+
result = Person.new.sanitize_for_mass_assignment(:a => "b")
|
|
23
|
+
assert_equal({ :a => "b" }, result)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
class ApplicationParamsArrayTest < Minitest::Test
|
|
4
|
+
def setup
|
|
5
|
+
ActionController::ParamsRegistry.clear!
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def teardown
|
|
9
|
+
ActionController::ParamsRegistry.clear!
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Test basic array support
|
|
13
|
+
def test_allow_array_attribute
|
|
14
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
15
|
+
allow :tags, array: true
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
attrs = test_class.permitted_attributes
|
|
19
|
+
assert_equal 1, attrs.length
|
|
20
|
+
assert_equal({ tags: [] }, attrs.first)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Test scalar and array attributes together
|
|
24
|
+
def test_mixed_scalar_and_array_attributes
|
|
25
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
26
|
+
allow :name
|
|
27
|
+
allow :tags, array: true
|
|
28
|
+
allow :email
|
|
29
|
+
allow :categories, array: true
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
attrs = test_class.permitted_attributes
|
|
33
|
+
assert_equal 4, attrs.length
|
|
34
|
+
assert attrs.include?(:name)
|
|
35
|
+
assert attrs.include?(:email)
|
|
36
|
+
assert attrs.include?({ tags: [] })
|
|
37
|
+
assert attrs.include?({ categories: [] })
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Test array with action filters
|
|
41
|
+
def test_array_with_only_filter
|
|
42
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
43
|
+
allow :tags, array: true, only: :create
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# With create action
|
|
47
|
+
attrs = test_class.permitted_attributes(action: :create)
|
|
48
|
+
assert_equal 1, attrs.length
|
|
49
|
+
assert_equal({ tags: [] }, attrs.first)
|
|
50
|
+
|
|
51
|
+
# With update action
|
|
52
|
+
attrs = test_class.permitted_attributes(action: :update)
|
|
53
|
+
assert_equal 0, attrs.length
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Test array with except filter
|
|
57
|
+
def test_array_with_except_filter
|
|
58
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
59
|
+
allow :tags, array: true, except: :destroy
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# With create action
|
|
63
|
+
attrs = test_class.permitted_attributes(action: :create)
|
|
64
|
+
assert_equal 1, attrs.length
|
|
65
|
+
assert_equal({ tags: [] }, attrs.first)
|
|
66
|
+
|
|
67
|
+
# With destroy action
|
|
68
|
+
attrs = test_class.permitted_attributes(action: :destroy)
|
|
69
|
+
assert_equal 0, attrs.length
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Test array inheritance
|
|
73
|
+
def test_array_inheritance
|
|
74
|
+
parent_class = Class.new(ActionController::ApplicationParams) do
|
|
75
|
+
allow :tags, array: true
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
child_class = Class.new(parent_class) do
|
|
79
|
+
allow :categories, array: true
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
attrs = child_class.permitted_attributes
|
|
83
|
+
assert_equal 2, attrs.length
|
|
84
|
+
assert attrs.include?({ tags: [] })
|
|
85
|
+
assert attrs.include?({ categories: [] })
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Test array can be denied in child class
|
|
89
|
+
def test_deny_inherited_array
|
|
90
|
+
parent_class = Class.new(ActionController::ApplicationParams) do
|
|
91
|
+
allow :tags, array: true
|
|
92
|
+
allow :name
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
child_class = Class.new(parent_class) do
|
|
96
|
+
deny :tags
|
|
97
|
+
allow :email
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
attrs = child_class.permitted_attributes
|
|
101
|
+
assert_equal 2, attrs.length
|
|
102
|
+
assert attrs.include?(:name)
|
|
103
|
+
assert attrs.include?(:email)
|
|
104
|
+
assert !attrs.include?({ tags: [] })
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Test transform_params with array attributes
|
|
108
|
+
def test_transform_params_with_array
|
|
109
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
110
|
+
def self.name
|
|
111
|
+
'ArticleParams'
|
|
112
|
+
end
|
|
113
|
+
allow :title
|
|
114
|
+
allow :tags, array: true
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
ActionController::ParamsRegistry.register('Article', test_class)
|
|
118
|
+
|
|
119
|
+
params = ActionController::Parameters.new(
|
|
120
|
+
article: {
|
|
121
|
+
title: 'Test Article',
|
|
122
|
+
tags: ['ruby', 'rails', 'testing'],
|
|
123
|
+
body: 'Should be filtered out'
|
|
124
|
+
}
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
permitted = params.require(:article).transform_params()
|
|
128
|
+
|
|
129
|
+
assert permitted.permitted?
|
|
130
|
+
assert_equal 'Test Article', permitted[:title]
|
|
131
|
+
assert_equal ['ruby', 'rails', 'testing'], permitted[:tags]
|
|
132
|
+
assert_nil permitted[:body]
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Test transform_params with empty array
|
|
136
|
+
def test_transform_params_with_empty_array
|
|
137
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
138
|
+
def self.name
|
|
139
|
+
'ArticleParams'
|
|
140
|
+
end
|
|
141
|
+
allow :title
|
|
142
|
+
allow :tags, array: true
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
ActionController::ParamsRegistry.register('Article', test_class)
|
|
146
|
+
|
|
147
|
+
params = ActionController::Parameters.new(
|
|
148
|
+
article: {
|
|
149
|
+
title: 'Test Article',
|
|
150
|
+
tags: []
|
|
151
|
+
}
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
permitted = params.require(:article).transform_params()
|
|
155
|
+
|
|
156
|
+
assert permitted.permitted?
|
|
157
|
+
assert_equal 'Test Article', permitted[:title]
|
|
158
|
+
assert_equal [], permitted[:tags]
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Test transform_params filters arrays with non-scalar elements
|
|
162
|
+
def test_transform_params_filters_non_scalar_array_elements
|
|
163
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
164
|
+
def self.name
|
|
165
|
+
'ArticleParams'
|
|
166
|
+
end
|
|
167
|
+
allow :title
|
|
168
|
+
allow :tags, array: true
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
ActionController::ParamsRegistry.register('Article', test_class)
|
|
172
|
+
|
|
173
|
+
params = ActionController::Parameters.new(
|
|
174
|
+
article: {
|
|
175
|
+
title: 'Test Article',
|
|
176
|
+
tags: ['valid', { invalid: 'hash' }, 'also_valid', ['nested', 'array']]
|
|
177
|
+
}
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
permitted = params.require(:article).transform_params()
|
|
181
|
+
|
|
182
|
+
assert permitted.permitted?
|
|
183
|
+
assert_equal 'Test Article', permitted[:title]
|
|
184
|
+
# Strong parameters filters out entire array if it contains non-scalar elements
|
|
185
|
+
assert_nil permitted[:tags]
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Test array attribute with additional_attrs
|
|
189
|
+
def test_array_with_additional_attrs
|
|
190
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
191
|
+
def self.name
|
|
192
|
+
'ArticleParams'
|
|
193
|
+
end
|
|
194
|
+
allow :title
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
ActionController::ParamsRegistry.register('Article', test_class)
|
|
198
|
+
|
|
199
|
+
params = ActionController::Parameters.new(
|
|
200
|
+
article: {
|
|
201
|
+
title: 'Test Article',
|
|
202
|
+
tags: ['ruby', 'rails']
|
|
203
|
+
}
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
# Add tags as additional attribute with array syntax
|
|
207
|
+
permitted = params.require(:article).transform_params(additional_attrs: [{ tags: [] }])
|
|
208
|
+
|
|
209
|
+
assert permitted.permitted?
|
|
210
|
+
assert_equal 'Test Article', permitted[:title]
|
|
211
|
+
assert_equal ['ruby', 'rails'], permitted[:tags]
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Test multiple array attributes
|
|
215
|
+
def test_multiple_array_attributes
|
|
216
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
217
|
+
def self.name
|
|
218
|
+
'ArticleParams'
|
|
219
|
+
end
|
|
220
|
+
allow :title
|
|
221
|
+
allow :tags, array: true
|
|
222
|
+
allow :categories, array: true
|
|
223
|
+
allow :author_ids, array: true
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
ActionController::ParamsRegistry.register('Article', test_class)
|
|
227
|
+
|
|
228
|
+
params = ActionController::Parameters.new(
|
|
229
|
+
article: {
|
|
230
|
+
title: 'Test Article',
|
|
231
|
+
tags: ['ruby', 'rails'],
|
|
232
|
+
categories: ['tech', 'programming'],
|
|
233
|
+
author_ids: [1, 2, 3]
|
|
234
|
+
}
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
permitted = params.require(:article).transform_params()
|
|
238
|
+
|
|
239
|
+
assert permitted.permitted?
|
|
240
|
+
assert_equal 'Test Article', permitted[:title]
|
|
241
|
+
assert_equal ['ruby', 'rails'], permitted[:tags]
|
|
242
|
+
assert_equal ['tech', 'programming'], permitted[:categories]
|
|
243
|
+
assert_equal [1, 2, 3], permitted[:author_ids]
|
|
244
|
+
end
|
|
245
|
+
end
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
|
|
3
|
+
class ApplicationParamsEdgeCasesTest < Minitest::Test
|
|
4
|
+
def setup
|
|
5
|
+
ActionController::ParamsRegistry.clear!
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def teardown
|
|
9
|
+
ActionController::ParamsRegistry.clear!
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Test duplicate allow calls
|
|
13
|
+
def test_duplicate_allow_calls_dont_duplicate_attributes
|
|
14
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
15
|
+
allow :name
|
|
16
|
+
allow :name
|
|
17
|
+
allow :name
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
assert_equal [:name], test_class.allowed_attributes
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Test duplicate deny calls
|
|
24
|
+
def test_duplicate_deny_calls_dont_duplicate_attributes
|
|
25
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
26
|
+
deny :admin
|
|
27
|
+
deny :admin
|
|
28
|
+
deny :admin
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
assert_equal [:admin], test_class.denied_attributes
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Test allow and deny same attribute
|
|
35
|
+
def test_deny_overrides_allow
|
|
36
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
37
|
+
allow :admin
|
|
38
|
+
deny :admin
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Deny should take precedence
|
|
42
|
+
assert !test_class.allowed?(:admin)
|
|
43
|
+
assert test_class.denied?(:admin)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Test order of allow/deny doesn't matter
|
|
47
|
+
def test_deny_before_allow_still_denies
|
|
48
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
49
|
+
deny :admin
|
|
50
|
+
allow :admin
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Deny should still take precedence
|
|
54
|
+
assert !test_class.allowed?(:admin)
|
|
55
|
+
assert test_class.denied?(:admin)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Test empty class
|
|
59
|
+
def test_empty_params_class_has_empty_lists
|
|
60
|
+
test_class = Class.new(ActionController::ApplicationParams)
|
|
61
|
+
|
|
62
|
+
assert_equal [], test_class.allowed_attributes
|
|
63
|
+
assert_equal [], test_class.denied_attributes
|
|
64
|
+
assert_equal({}, test_class.flags)
|
|
65
|
+
assert_equal Set.new, test_class.allowed_metadata
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Test flag overwriting
|
|
69
|
+
def test_flag_can_be_overwritten
|
|
70
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
71
|
+
flag :test_flag, true
|
|
72
|
+
flag :test_flag, false
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
assert_equal false, test_class.flag?(:test_flag)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Test flag with different value types
|
|
79
|
+
def test_flag_with_string_value
|
|
80
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
81
|
+
flag :status, 'active'
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
assert_equal 'active', test_class.flag?(:status)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def test_flag_with_numeric_value
|
|
88
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
89
|
+
flag :max_count, 100
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
assert_equal 100, test_class.flag?(:max_count)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def test_flag_with_array_value
|
|
96
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
97
|
+
flag :allowed_actions, [:create, :update]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
assert_equal [:create, :update], test_class.flag?(:allowed_actions)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def test_flag_with_hash_value
|
|
104
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
105
|
+
flag :config, { min: 1, max: 10 }
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
assert_equal({ min: 1, max: 10 }, test_class.flag?(:config))
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Test attribute options with different formats
|
|
112
|
+
def test_allow_with_only_single_action
|
|
113
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
114
|
+
allow :field, only: :create
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
assert_includes test_class.permitted_attributes(action: :create), :field
|
|
118
|
+
refute_includes test_class.permitted_attributes(action: :update), :field
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def test_allow_with_only_array_of_actions
|
|
122
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
123
|
+
allow :field, only: [:create, :update]
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
assert_includes test_class.permitted_attributes(action: :create), :field
|
|
127
|
+
assert_includes test_class.permitted_attributes(action: :update), :field
|
|
128
|
+
refute_includes test_class.permitted_attributes(action: :destroy), :field
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def test_allow_with_except_single_action
|
|
132
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
133
|
+
allow :field, except: :destroy
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
assert_includes test_class.permitted_attributes(action: :create), :field
|
|
137
|
+
assert_includes test_class.permitted_attributes(action: :update), :field
|
|
138
|
+
refute_includes test_class.permitted_attributes(action: :destroy), :field
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def test_allow_with_except_array_of_actions
|
|
142
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
143
|
+
allow :field, except: [:destroy, :delete]
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
assert_includes test_class.permitted_attributes(action: :create), :field
|
|
147
|
+
refute_includes test_class.permitted_attributes(action: :destroy), :field
|
|
148
|
+
refute_includes test_class.permitted_attributes(action: :delete), :field
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Test multiple attributes with different options
|
|
152
|
+
def test_multiple_attributes_with_different_action_filters
|
|
153
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
154
|
+
allow :name
|
|
155
|
+
allow :email
|
|
156
|
+
allow :status, only: :create
|
|
157
|
+
allow :updated_by, except: :create
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
create_attrs = test_class.permitted_attributes(action: :create)
|
|
161
|
+
assert_includes create_attrs, :name
|
|
162
|
+
assert_includes create_attrs, :email
|
|
163
|
+
assert_includes create_attrs, :status
|
|
164
|
+
refute_includes create_attrs, :updated_by
|
|
165
|
+
|
|
166
|
+
update_attrs = test_class.permitted_attributes(action: :update)
|
|
167
|
+
assert_includes update_attrs, :name
|
|
168
|
+
assert_includes update_attrs, :email
|
|
169
|
+
refute_includes update_attrs, :status
|
|
170
|
+
assert_includes update_attrs, :updated_by
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Test inheritance with complex scenarios
|
|
174
|
+
def test_deep_inheritance_chain
|
|
175
|
+
grandparent = Class.new(ActionController::ApplicationParams) do
|
|
176
|
+
allow :id
|
|
177
|
+
flag :grandparent_flag, true
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
parent = Class.new(grandparent) do
|
|
181
|
+
allow :name
|
|
182
|
+
flag :parent_flag, true
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
child = Class.new(parent) do
|
|
186
|
+
allow :email
|
|
187
|
+
flag :child_flag, true
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Child should have all attributes
|
|
191
|
+
assert_includes child.allowed_attributes, :id
|
|
192
|
+
assert_includes child.allowed_attributes, :name
|
|
193
|
+
assert_includes child.allowed_attributes, :email
|
|
194
|
+
|
|
195
|
+
# Child should have all flags
|
|
196
|
+
assert child.flag?(:grandparent_flag)
|
|
197
|
+
assert child.flag?(:parent_flag)
|
|
198
|
+
assert child.flag?(:child_flag)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def test_child_modifications_dont_affect_parent
|
|
202
|
+
parent = Class.new(ActionController::ApplicationParams) do
|
|
203
|
+
allow :name
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
child = Class.new(parent) do
|
|
207
|
+
allow :email
|
|
208
|
+
deny :name
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Parent should remain unchanged
|
|
212
|
+
assert_includes parent.allowed_attributes, :name
|
|
213
|
+
assert_equal [], parent.denied_attributes
|
|
214
|
+
assert parent.allowed?(:name)
|
|
215
|
+
|
|
216
|
+
# Child should have modifications
|
|
217
|
+
assert_includes child.allowed_attributes, :name
|
|
218
|
+
assert_includes child.allowed_attributes, :email
|
|
219
|
+
assert_includes child.denied_attributes, :name
|
|
220
|
+
assert !child.allowed?(:name)
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# Test symbol/string conversions
|
|
224
|
+
def test_allow_converts_string_to_symbol
|
|
225
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
226
|
+
allow 'name'
|
|
227
|
+
allow 'email'
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
assert_includes test_class.allowed_attributes, :name
|
|
231
|
+
assert_includes test_class.allowed_attributes, :email
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def test_deny_converts_string_to_symbol
|
|
235
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
236
|
+
deny 'admin'
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
assert_includes test_class.denied_attributes, :admin
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def test_flag_converts_string_name_to_symbol
|
|
243
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
244
|
+
flag 'test_flag', true
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
assert test_class.flag?(:test_flag)
|
|
248
|
+
assert test_class.flag?('test_flag')
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
# Test permitted_attributes without action filter
|
|
252
|
+
def test_permitted_attributes_without_action_includes_all
|
|
253
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
254
|
+
allow :name
|
|
255
|
+
allow :status, only: :create
|
|
256
|
+
allow :email, except: :destroy
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
attrs = test_class.permitted_attributes
|
|
260
|
+
assert_includes attrs, :name
|
|
261
|
+
assert_includes attrs, :status
|
|
262
|
+
assert_includes attrs, :email
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
# Test metadata edge cases
|
|
266
|
+
def test_metadata_with_duplicate_keys
|
|
267
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
268
|
+
metadata :ip_address
|
|
269
|
+
metadata :ip_address
|
|
270
|
+
metadata :ip_address
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# Should only be stored once
|
|
274
|
+
assert_equal 1, test_class.allowed_metadata.size
|
|
275
|
+
assert test_class.metadata_allowed?(:ip_address)
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def test_metadata_with_mixed_symbol_string
|
|
279
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
280
|
+
metadata :key1
|
|
281
|
+
metadata 'key2'
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
assert test_class.metadata_allowed?(:key1)
|
|
285
|
+
assert test_class.metadata_allowed?('key1')
|
|
286
|
+
assert test_class.metadata_allowed?(:key2)
|
|
287
|
+
assert test_class.metadata_allowed?('key2')
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# Test attribute_options with non-existent attribute
|
|
291
|
+
def test_attribute_options_for_non_existent_attribute
|
|
292
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
293
|
+
allow :name
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
opts = test_class.attribute_options(:non_existent)
|
|
297
|
+
assert_equal({}, opts)
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Test attribute_options overwriting
|
|
301
|
+
def test_allow_same_attribute_twice_with_different_options
|
|
302
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
303
|
+
allow :field, only: :create
|
|
304
|
+
allow :field, except: :destroy
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# Second call should overwrite options
|
|
308
|
+
opts = test_class.attribute_options(:field)
|
|
309
|
+
assert_nil opts[:only]
|
|
310
|
+
assert_equal [:destroy], opts[:except]
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
# Test empty action filters
|
|
314
|
+
def test_allow_with_empty_only_array
|
|
315
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
316
|
+
allow :field, only: []
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
# Empty array should exclude field from all actions
|
|
320
|
+
refute_includes test_class.permitted_attributes(action: :create), :field
|
|
321
|
+
refute_includes test_class.permitted_attributes(action: :update), :field
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def test_allow_with_empty_except_array
|
|
325
|
+
test_class = Class.new(ActionController::ApplicationParams) do
|
|
326
|
+
allow :field, except: []
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
# Empty array should include field in all actions
|
|
330
|
+
assert_includes test_class.permitted_attributes(action: :create), :field
|
|
331
|
+
assert_includes test_class.permitted_attributes(action: :update), :field
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
# Test complex inheritance with metadata
|
|
335
|
+
def test_inheritance_with_metadata_additions
|
|
336
|
+
parent = Class.new(ActionController::ApplicationParams) do
|
|
337
|
+
metadata :parent_meta
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
child = Class.new(parent) do
|
|
341
|
+
metadata :child_meta
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
assert child.metadata_allowed?(:parent_meta)
|
|
345
|
+
assert child.metadata_allowed?(:child_meta)
|
|
346
|
+
assert parent.metadata_allowed?(:parent_meta)
|
|
347
|
+
assert !parent.metadata_allowed?(:child_meta)
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
# Test inheritance with attribute_options
|
|
351
|
+
def test_inheritance_copies_attribute_options
|
|
352
|
+
parent = Class.new(ActionController::ApplicationParams) do
|
|
353
|
+
allow :field, only: :create
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
child = Class.new(parent)
|
|
357
|
+
|
|
358
|
+
opts = child.attribute_options(:field)
|
|
359
|
+
assert_equal [:create], opts[:only]
|
|
360
|
+
end
|
|
361
|
+
end
|