strongly_typed_parameters 0.0.1

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.
@@ -0,0 +1,4 @@
1
+ require 'action_controller/parameters'
2
+ require 'active_model/forbidden_attributes_protection'
3
+ require 'strongly_typed_parameters/railtie'
4
+ require 'strongly_typed_parameters/boolean'
@@ -0,0 +1,12 @@
1
+ #marker module to identify boolean objects.
2
+
3
+ module Boolean
4
+ end
5
+
6
+ class TrueClass
7
+ include Boolean
8
+ end
9
+
10
+ class FalseClass
11
+ include Boolean
12
+ end
@@ -0,0 +1,17 @@
1
+ require 'rails/railtie'
2
+
3
+ module StronglyTypedParameters
4
+ class Railtie < ::Rails::Railtie
5
+ if config.respond_to?(:app_generators)
6
+ config.app_generators.scaffold_controller = :strongly_typed_parameters_controller
7
+ else
8
+ config.generators.scaffold_controller = :strongly_typed_parameters_controller
9
+ end
10
+
11
+ initializer "strong_parameters.config", :before => "action_controller.set_configs" do |app|
12
+ ActionController::Parameters.action_on_unpermitted_parameters = app.config.action_controller.delete(:action_on_unpermitted_parameters) do
13
+ (Rails.env.test? || Rails.env.development?) ? :log : false
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ module StronglyTypedParameters
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,30 @@
1
+ require 'test_helper'
2
+
3
+ class BooksController < ActionController::Base
4
+ def create
5
+ params.require(:book).require(:name)
6
+ head :ok
7
+ end
8
+ end
9
+
10
+ class ActionControllerRequiredParamsTest < ActionController::TestCase
11
+ tests BooksController
12
+
13
+ test "missing required parameters will raise exception" do
14
+ post :create, { :magazine => { :name => "Mjallo!" } }
15
+ assert_response :bad_request
16
+
17
+ post :create, { :book => { :title => "Mjallo!" } }
18
+ assert_response :bad_request
19
+ end
20
+
21
+ test "required parameters that are present will not raise" do
22
+ post :create, { :book => { :name => "Mjallo!" } }
23
+ assert_response :ok
24
+ end
25
+
26
+ test "missing parameters will be mentioned in the return" do
27
+ post :create, { :magazine => { :name => "Mjallo!" } }
28
+ assert_equal "Required parameter missing: book", response.body
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ class PeopleController < ActionController::Base
4
+ def create
5
+ render :text => params[:person].permitted? ? "untainted" : "tainted"
6
+ end
7
+
8
+ def create_with_permit
9
+ render :text => params[:person].permit(:name).permitted? ? "untainted" : "tainted"
10
+ end
11
+ end
12
+
13
+ class ActionControllerTaintedParamsTest < ActionController::TestCase
14
+ tests PeopleController
15
+
16
+ test "parameters are tainted" do
17
+ post :create, { :person => { :name => "Mjallo!" } }
18
+ assert_equal "tainted", response.body
19
+ end
20
+
21
+ test "parameters can be permitted and are then not tainted" do
22
+ post :create_with_permit, { :person => { :name => "Mjallo!" } }
23
+ assert_equal "untainted", response.body
24
+ end
25
+ end
@@ -0,0 +1,30 @@
1
+ require 'test_helper'
2
+
3
+ class Person
4
+ include ActiveModel::MassAssignmentSecurity
5
+ include ActiveModel::ForbiddenAttributesProtection
6
+
7
+ public :sanitize_for_mass_assignment
8
+ end
9
+
10
+ class ActiveModelMassUpdateProtectionTest < ActiveSupport::TestCase
11
+ test "forbidden attributes cannot be used for mass updating" do
12
+ assert_raises(ActiveModel::ForbiddenAttributes) do
13
+ Person.new.sanitize_for_mass_assignment(ActionController::Parameters.new(:a => "b"))
14
+ end
15
+ end
16
+
17
+ test "permitted attributes can be used for mass updating" do
18
+ assert_nothing_raised do
19
+ assert_equal({ "a" => "b" },
20
+ Person.new.sanitize_for_mass_assignment(ActionController::Parameters.new(:a => "b").permit(:a)))
21
+ end
22
+ end
23
+
24
+ test "regular attributes should still be allowed" do
25
+ assert_nothing_raised do
26
+ assert_equal({ :a => "b" },
27
+ Person.new.sanitize_for_mass_assignment(:a => "b"))
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,28 @@
1
+ require 'test_helper'
2
+ require 'action_controller/parameters'
3
+
4
+ class Column
5
+ attr_accessor :name
6
+ attr_accessor :klass
7
+ def initialize(hsh)
8
+ hsh.each do |name, klass|
9
+ @name = name
10
+ @klass = klass
11
+ end
12
+ end
13
+ end
14
+
15
+ class User
16
+ def self.columns
17
+ [Column.new("id" => Fixnum), Column.new("name" => String)]
18
+ end
19
+ end
20
+
21
+ class ActiveModelSmartTypeDefaultingTest < ActiveSupport::TestCase
22
+ test "if no types are given but the parent object shares a name with a model, attribute types are used" do
23
+ params = ActionController::Parameters.new(:user => [:id => 1234])
24
+ permitted = params.permit(:user => [:id, :name])
25
+ assert_equal permitted[:user][0][:id], 1234
26
+ assert_nil permitted[:user][0][:name]
27
+ end
28
+ end
@@ -0,0 +1,38 @@
1
+ #FIXME: This errors due to Mocha.
2
+
3
+ =begin
4
+
5
+ require 'rails/generators/test_case'
6
+ require 'generators/rails/strong_parameters_controller_generator'
7
+
8
+ class StrongParametersControllerGeneratorTest < Rails::Generators::TestCase
9
+ tests Rails::Generators::StrongParametersControllerGenerator
10
+ arguments %w(User name:string age:integer --orm=none)
11
+ destination File.expand_path("../tmp", File.dirname(__FILE__))
12
+ setup :prepare_destination
13
+
14
+ def test_controller_content
15
+ Rails.stubs(:application).returns(nil)
16
+ run_generator
17
+
18
+ assert_file "app/controllers/users_controller.rb" do |content|
19
+
20
+ assert_instance_method :create, content do |m|
21
+ assert_match '@user = User.new(user_params)', m
22
+ assert_match '@user.save', m
23
+ assert_match '@user.errors', m
24
+ end
25
+
26
+ assert_instance_method :update, content do |m|
27
+ assert_match '@user = User.find(params[:id])', m
28
+ assert_match '@user.update_attributes(user_params)', m
29
+ assert_match '@user.errors', m
30
+ end
31
+
32
+ assert_match 'def user_params', content
33
+ assert_match 'params.require(:user).permit(:age, :name)', content
34
+ end
35
+ end
36
+ end
37
+
38
+ =end
@@ -0,0 +1,6 @@
1
+ source :rubygems
2
+ gemspec :path => "./../.."
3
+
4
+ gem "actionpack", "~> 3.0.0"
5
+ gem "railties", "~> 3.0.0"
6
+ gem "activemodel", "~> 3.0.0"
@@ -0,0 +1,62 @@
1
+ PATH
2
+ remote: /Users/mgrosser/code/tools/strong_parameters
3
+ specs:
4
+ strong_parameters (0.1.6.dev)
5
+ actionpack (~> 3.0)
6
+ activemodel (~> 3.0)
7
+ railties (~> 3.0)
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ abstract (1.0.0)
13
+ actionpack (3.0.17)
14
+ activemodel (= 3.0.17)
15
+ activesupport (= 3.0.17)
16
+ builder (~> 2.1.2)
17
+ erubis (~> 2.6.6)
18
+ i18n (~> 0.5.0)
19
+ rack (~> 1.2.5)
20
+ rack-mount (~> 0.6.14)
21
+ rack-test (~> 0.5.7)
22
+ tzinfo (~> 0.3.23)
23
+ activemodel (3.0.17)
24
+ activesupport (= 3.0.17)
25
+ builder (~> 2.1.2)
26
+ i18n (~> 0.5.0)
27
+ activesupport (3.0.17)
28
+ builder (2.1.2)
29
+ erubis (2.6.6)
30
+ abstract (>= 1.0.0)
31
+ i18n (0.5.0)
32
+ json (1.7.5)
33
+ metaclass (0.0.1)
34
+ mocha (0.12.7)
35
+ metaclass (~> 0.0.1)
36
+ rack (1.2.5)
37
+ rack-mount (0.6.14)
38
+ rack (>= 1.0.0)
39
+ rack-test (0.5.7)
40
+ rack (>= 1.0)
41
+ railties (3.0.17)
42
+ actionpack (= 3.0.17)
43
+ activesupport (= 3.0.17)
44
+ rake (>= 0.8.7)
45
+ rdoc (~> 3.4)
46
+ thor (~> 0.14.4)
47
+ rake (10.0.1)
48
+ rdoc (3.12)
49
+ json (~> 1.4)
50
+ thor (0.14.6)
51
+ tzinfo (0.3.35)
52
+
53
+ PLATFORMS
54
+ ruby
55
+
56
+ DEPENDENCIES
57
+ actionpack (~> 3.0.0)
58
+ activemodel (~> 3.0.0)
59
+ mocha (~> 0.12.0)
60
+ railties (~> 3.0.0)
61
+ rake
62
+ strong_parameters!
@@ -0,0 +1,6 @@
1
+ source :rubygems
2
+ gemspec :path => "./../.."
3
+
4
+ gem "actionpack", "~> 3.1.0"
5
+ gem "railties", "~> 3.1.0"
6
+ gem "activemodel", "~> 3.1.0"
@@ -0,0 +1,6 @@
1
+ source :rubygems
2
+ gemspec :path => "./../.."
3
+
4
+ gem "actionpack", "~> 3.2.0"
5
+ gem "railties", "~> 3.2.0"
6
+ gem "activemodel", "~> 3.2.0"
@@ -0,0 +1,50 @@
1
+ require 'test_helper'
2
+ require 'action_controller/parameters'
3
+
4
+ class LogOnUnpermittedParamsTest < ActiveSupport::TestCase
5
+ def setup
6
+ ActionController::Parameters.action_on_unpermitted_parameters = :log
7
+ end
8
+
9
+ def teardown
10
+ ActionController::Parameters.action_on_unpermitted_parameters = false
11
+ end
12
+
13
+ test "logs on unexpected params" do
14
+ params = ActionController::Parameters.new({
15
+ :book => { :pages => 65 },
16
+ :fishing => "Turnips"
17
+ })
18
+
19
+ assert_logged("Unpermitted parameters: fishing") do
20
+ params.permit(:book => [:pages])
21
+ end
22
+ end
23
+
24
+ test "logs on unexpected nested params" do
25
+ params = ActionController::Parameters.new({
26
+ :book => { :pages => 65, :title => "Green Cats and where to find then." }
27
+ })
28
+
29
+ assert_logged("Unpermitted parameters: title") do
30
+ params.permit(:book => [:pages => Numeric])
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def assert_logged(message)
37
+ old_logger = ActionController::Base.logger
38
+ log = StringIO.new
39
+ ActionController::Base.logger = Logger.new(log)
40
+
41
+ begin
42
+ yield
43
+
44
+ log.rewind
45
+ assert_match message, log.read
46
+ ensure
47
+ ActionController::Base.logger = old_logger
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,38 @@
1
+ require 'test_helper'
2
+ require 'action_controller/parameters'
3
+
4
+ class MultiParameterAttributesTest < ActiveSupport::TestCase
5
+ test "permitted multi-parameter attribute keys" do
6
+ params = ActionController::Parameters.new({
7
+ :book => {
8
+ "shipped_at(1i)" => "2012",
9
+ "shipped_at(2i)" => "3",
10
+ "shipped_at(3i)" => "25",
11
+ "shipped_at(4i)" => "10",
12
+ "shipped_at(5i)" => "15",
13
+ "published_at(1i)" => "1999",
14
+ "published_at(2i)" => "2",
15
+ "published_at(3i)" => "5",
16
+ "price(1)" => "R$",
17
+ "price(2f)" => "2.02"
18
+ }
19
+ })
20
+ permitted = params.permit :book => [ :shipped_at, :price ]
21
+
22
+ assert permitted.permitted?
23
+
24
+ assert_equal "2012", permitted[:book]["shipped_at(1i)"]
25
+ assert_equal "3", permitted[:book]["shipped_at(2i)"]
26
+ assert_equal "25", permitted[:book]["shipped_at(3i)"]
27
+ assert_equal "10", permitted[:book]["shipped_at(4i)"]
28
+ assert_equal "15", permitted[:book]["shipped_at(5i)"]
29
+
30
+ assert_equal "R$", permitted[:book]["price(1)"]
31
+ assert_equal "2.02", permitted[:book]["price(2f)"]
32
+
33
+ assert_nil permitted[:book]["published_at(1i)"]
34
+ assert_nil permitted[:book]["published_at(2i)"]
35
+ assert_nil permitted[:book]["published_at(3i)"]
36
+ end
37
+ end
38
+
@@ -0,0 +1,264 @@
1
+ require 'test_helper'
2
+ require 'action_controller/parameters'
3
+ require 'action_dispatch/http/upload'
4
+
5
+ class NestedParametersTest < ActiveSupport::TestCase
6
+ def assert_filtered_out(params, key)
7
+ assert !params.has_key?(key), "key #{key.inspect} has not been filtered out"
8
+ end
9
+
10
+ #
11
+ # --- Basic interface --------------------------------------------------------
12
+ #
13
+
14
+ # --- nothing ----------------------------------------------------------------
15
+
16
+ test 'if nothing is permitted, the hash becomes empty' do
17
+ params = ActionController::Parameters.new(:id => '1234')
18
+ permitted = params.permit
19
+ permitted.permitted?
20
+ permitted.empty?
21
+ end
22
+
23
+ # --- key --------------------------------------------------------------------
24
+
25
+ test 'key: unexpected types are filtered out' do
26
+ params = ActionController::Parameters.new(:id => 1234, :token => 0)
27
+ permitted = params.permit(:id => Numeric, :token => String)
28
+ assert_equal 1234, permitted[:id]
29
+ assert_filtered_out permitted, :token
30
+ end
31
+
32
+ test 'key: unknown keys are filtered out' do
33
+ params = ActionController::Parameters.new(:id => '1234', :injected => 'injected')
34
+ permitted = params.permit(:id)
35
+ assert_equal '1234', permitted[:id]
36
+ assert_filtered_out permitted, :injected
37
+ end
38
+
39
+ test 'key: arrays are filtered out' do
40
+ [[], [1], ['1']].each do |array|
41
+ params = ActionController::Parameters.new(:id => array)
42
+ permitted = params.permit(:id)
43
+ assert_filtered_out permitted, :id
44
+
45
+ %w(i f).each do |suffix|
46
+ params = ActionController::Parameters.new("foo(000#{suffix})" => array)
47
+ permitted = params.permit(:foo)
48
+ assert_filtered_out permitted, "foo(000#{suffix})"
49
+ end
50
+ end
51
+ end
52
+
53
+ test 'key: hashes are filtered out' do
54
+ [{}, {:foo => 1}, {:foo => 'bar'}].each do |hash|
55
+ params = ActionController::Parameters.new(:id => hash)
56
+ permitted = params.permit(:id)
57
+ assert_filtered_out permitted, :id
58
+
59
+ %w(i f).each do |suffix|
60
+ params = ActionController::Parameters.new("foo(000#{suffix})" => hash)
61
+ permitted = params.permit(:foo)
62
+ assert_filtered_out permitted, "foo(000#{suffix})"
63
+ end
64
+ end
65
+ end
66
+
67
+ test 'key: non-permitted scalar values are filtered out' do
68
+ params = ActionController::Parameters.new(:id => Object.new)
69
+ permitted = params.permit(:id)
70
+ assert_filtered_out permitted, :id
71
+
72
+ %w(i f).each do |suffix|
73
+ params = ActionController::Parameters.new("foo(000#{suffix})" => Object.new)
74
+ permitted = params.permit(:foo)
75
+ assert_filtered_out permitted, "foo(000#{suffix})"
76
+ end
77
+ end
78
+
79
+ test 'key: Boolean matches only true and false' do
80
+ params = ActionController::Parameters.new(:happy => true)
81
+ permitted = params.permit(:happy => Boolean)
82
+ assert_equal true, permitted[:happy]
83
+
84
+ params = ActionController::Parameters.new(:happy => false)
85
+ permitted = params.permit(:happy => Boolean)
86
+ assert_equal false, permitted[:happy]
87
+
88
+ params = ActionController::Parameters.new(:happy => Object.new)
89
+ permitted = params.permit(:happy => Boolean)
90
+ assert_filtered_out permitted, :happy
91
+
92
+ end
93
+
94
+ test 'key: it is not assigned if not present in params' do
95
+ params = ActionController::Parameters.new(:name => 'Joe')
96
+ permitted = params.permit(:id)
97
+ assert !permitted.has_key?(:id)
98
+ end
99
+
100
+ #
101
+ # --- Nesting ----------------------------------------------------------------
102
+ #
103
+
104
+ test "permitted nested parameters" do
105
+ params = ActionController::Parameters.new({
106
+ :book => {
107
+ :title => "Romeo and Juliet",
108
+ :authors => [{
109
+ :name => "William Shakespeare",
110
+ :born => "1564-04-26"
111
+ }, {
112
+ :name => "Christopher Marlowe"
113
+ }, {
114
+ :name => %w(malicious injected names)
115
+ }],
116
+ :details => {
117
+ :pages => 200,
118
+ :genre => "Tragedy"
119
+ }
120
+ },
121
+ :magazine => "Mjallo!"
122
+ })
123
+
124
+ permitted = params.permit :book => [ :title, { :authors => [ :name ] }, { :details => {:pages => Numeric} } ]
125
+
126
+ assert permitted.permitted?
127
+ assert_equal "Romeo and Juliet", permitted[:book][:title]
128
+ assert_equal "William Shakespeare", permitted[:book][:authors][0][:name]
129
+ assert_equal "Christopher Marlowe", permitted[:book][:authors][1][:name]
130
+ assert_equal 200, permitted[:book][:details][:pages]
131
+
132
+ assert_filtered_out permitted[:book][:authors][2], :name
133
+
134
+ assert_filtered_out permitted, :magazine
135
+ assert_filtered_out permitted[:book][:details], :genre
136
+ assert_filtered_out permitted[:book][:authors][0], :born
137
+ end
138
+
139
+ test "permitted nested parameters with a string or a symbol as a key" do
140
+ params = ActionController::Parameters.new({
141
+ :book => {
142
+ 'authors' => [
143
+ { :name => "William Shakespeare", :born => "1564-04-26" },
144
+ { :name => "Christopher Marlowe" }
145
+ ]
146
+ }
147
+ })
148
+
149
+ permitted = params.permit :book => [ { 'authors' => [ :name ] } ]
150
+
151
+ assert_equal "William Shakespeare", permitted[:book]['authors'][0][:name]
152
+ assert_equal "William Shakespeare", permitted[:book][:authors][0][:name]
153
+ assert_equal "Christopher Marlowe", permitted[:book]['authors'][1][:name]
154
+ assert_equal "Christopher Marlowe", permitted[:book][:authors][1][:name]
155
+
156
+ permitted = params.permit :book => [ { :authors => [ :name ] } ]
157
+
158
+ assert_equal "William Shakespeare", permitted[:book]['authors'][0][:name]
159
+ assert_equal "William Shakespeare", permitted[:book][:authors][0][:name]
160
+ assert_equal "Christopher Marlowe", permitted[:book]['authors'][1][:name]
161
+ assert_equal "Christopher Marlowe", permitted[:book][:authors][1][:name]
162
+ end
163
+
164
+ test "nested arrays with strings" do
165
+ params = ActionController::Parameters.new({
166
+ :book => {
167
+ :genres => ["Tragedy"]
168
+ }
169
+ })
170
+
171
+ permitted = params.permit :book => {:genres => [String]}
172
+ assert_equal ["Tragedy"], permitted[:book][:genres]
173
+ end
174
+
175
+ test "permit may specify symbols or strings" do
176
+ params = ActionController::Parameters.new({
177
+ :book => {
178
+ :title => "Romeo and Juliet",
179
+ :author => "William Shakespeare"
180
+ },
181
+ :magazine => "Shakespeare Today"
182
+ })
183
+
184
+ permitted = params.permit({ :book => ["title", :author] }, "magazine")
185
+ assert_equal "Romeo and Juliet", permitted[:book][:title]
186
+ assert_equal "William Shakespeare", permitted[:book][:author]
187
+ assert_equal "Shakespeare Today", permitted[:magazine]
188
+ end
189
+
190
+ test "nested array with strings that should be hashes" do
191
+ params = ActionController::Parameters.new({
192
+ :book => {
193
+ :genres => ["Tragedy"]
194
+ }
195
+ })
196
+
197
+ permitted = params.permit :book => { :genres => :type }
198
+ assert permitted[:book][:genres].empty?
199
+ end
200
+
201
+ test "nested array with strings that should be hashes and additional values" do
202
+ params = ActionController::Parameters.new({
203
+ :book => {
204
+ :title => "Romeo and Juliet",
205
+ :genres => ["Tragedy"]
206
+ }
207
+ })
208
+
209
+ permitted = params.permit :book => [ :title, { :genres => :type } ]
210
+ assert_equal "Romeo and Juliet", permitted[:book][:title]
211
+ assert permitted[:book][:genres].empty?
212
+ end
213
+
214
+ test "nested string that should be a hash" do
215
+ params = ActionController::Parameters.new({
216
+ :book => {
217
+ :genre => "Tragedy"
218
+ }
219
+ })
220
+
221
+ permitted = params.permit :book => { :genre => :type }
222
+ assert_nil permitted[:book][:genre]
223
+ end
224
+
225
+ test "fields_for_style_nested_params" do
226
+ params = ActionController::Parameters.new({
227
+ :book => {
228
+ :authors_attributes => {
229
+ :'0' => { :name => 'William Shakespeare', :age_of_death => '52' },
230
+ :'1' => { :name => 'Unattributed Assistant' },
231
+ :'2' => { :name => %w(injected names)}
232
+ }
233
+ }
234
+ })
235
+ permitted = params.permit :book => { :authors_attributes => [ :name ] }
236
+
237
+ assert_not_nil permitted[:book][:authors_attributes]['0']
238
+ assert_not_nil permitted[:book][:authors_attributes]['1']
239
+ assert permitted[:book][:authors_attributes]['2'].empty?
240
+ assert_equal 'William Shakespeare', permitted[:book][:authors_attributes]['0'][:name]
241
+ assert_equal 'Unattributed Assistant', permitted[:book][:authors_attributes]['1'][:name]
242
+
243
+ assert_filtered_out permitted[:book][:authors_attributes]['0'], :age_of_death
244
+ end
245
+
246
+ test "fields_for_style_nested_params with negative numbers" do
247
+ params = ActionController::Parameters.new({
248
+ :book => {
249
+ :authors_attributes => {
250
+ :'-1' => { :name => 'William Shakespeare', :age_of_death => '52' },
251
+ :'-2' => { :name => 'Unattributed Assistant' }
252
+ }
253
+ }
254
+ })
255
+ permitted = params.permit :book => { :authors_attributes => [:name] }
256
+
257
+ assert_not_nil permitted[:book][:authors_attributes]['-1']
258
+ assert_not_nil permitted[:book][:authors_attributes]['-2']
259
+ assert_equal 'William Shakespeare', permitted[:book][:authors_attributes]['-1'][:name]
260
+ assert_equal 'Unattributed Assistant', permitted[:book][:authors_attributes]['-2'][:name]
261
+
262
+ assert_filtered_out permitted[:book][:authors_attributes]['-1'], :age_of_death
263
+ end
264
+ end