33require 'spec_helper'
44
55RSpec . describe StructuredParams ::Params do
6- # Test parameter class definitions
7- let ( :address_parameter_class ) do
8- Class . new ( described_class ) do
9- def self . name
10- 'AddressParameter'
11- end
12-
13- attribute :postal_code , :string
14- attribute :prefecture , :string
15- attribute :city , :string
16- attribute :street , :string
17-
18- validates :postal_code , presence : true , format : { with : /\A \d {3}-\d {4}\z / }
19- validates :prefecture , presence : true
20- validates :city , presence : true
21- end
22- end
23-
24- let ( :hobby_parameter_class ) do
25- Class . new ( described_class ) do
26- def self . name
27- 'HobbyParameter'
28- end
29-
30- attribute :name , :string
31- attribute :level , :integer
32- attribute :years_experience , :integer
33-
34- validates :name , presence : true
35- validates :level , inclusion : { in : 1 ..3 }
36- validates :years_experience , numericality : { greater_than_or_equal_to : 0 }
37- end
38- end
39-
40- let ( :user_parameter_class ) do
41- address_class = address_parameter_class
42- hobby_class = hobby_parameter_class
43-
44- Class . new ( described_class ) do
45- def self . name
46- 'UserParameter'
47- end
48-
49- attribute :name , :string
50- attribute :email , :string
51- attribute :age , :integer
52- attribute :address , :object , value_class : address_class
53- attribute :hobbies , :array , value_class : hobby_class
54- attribute :tags , :array , value_type : :string
55-
56- validates :name , presence : true , length : { maximum : 50 }
57- validates :email , presence : true , format : { with : URI ::MailTo ::EMAIL_REGEXP }
58- validates :age , numericality : { greater_than : 0 }
59- end
60- end
61-
626 describe '.permit_attribute_names' do
63- subject ( :permit_attribute_names ) { user_parameter_class . permit_attribute_names }
7+ subject ( :permit_attribute_names ) do
8+ UserParameter . permit_attribute_names
9+ end
6410
6511 it {
6612 expect ( permit_attribute_names ) . to eq ( [ :name , :email , :age ,
@@ -84,14 +30,14 @@ def self.name
8430 } ,
8531 hobbies : [
8632 { name : 'programming' , level : 3 , years_experience : 10 } ,
87- { name : '読書 ' , level : 2 , years_experience : 5 }
33+ { name : 'Web ' , level : 2 , years_experience : 5 }
8834 ] ,
89- tags : %w[ Ruby Rails 技術書 ]
35+ tags : %w[ Ruby Rails Web ]
9036 }
9137 end
9238
9339 context 'with valid parameters' do
94- subject ( :user_param ) { user_parameter_class . new ( valid_params ) }
40+ subject ( :user_param ) { build ( :user_parameter , ** valid_params ) }
9541
9642 it {
9743 expect ( user_param ) . to have_attributes (
@@ -104,7 +50,7 @@ def self.name
10450 context 'with object parameters' do
10551 subject ( :address ) { user_param . address }
10652
107- it { is_expected . to be_instance_of ( address_parameter_class ) }
53+ it { is_expected . to be_instance_of ( AddressParameter ) }
10854
10955 it {
11056 expect ( address ) . to have_attributes (
@@ -120,20 +66,20 @@ def self.name
12066 subject ( :hobbies ) { user_param . hobbies }
12167
12268 it { is_expected . to be_an ( Array ) }
123- it { is_expected . to contain_exactly ( hobby_parameter_class , hobby_parameter_class ) }
69+ it { is_expected . to contain_exactly ( HobbyParameter , HobbyParameter ) }
12470 it { expect ( hobbies [ 0 ] ) . to have_attributes ( name : 'programming' , level : 3 , years_experience : 10 ) }
125- it { expect ( hobbies [ 1 ] ) . to have_attributes ( name : '読書 ' , level : 2 , years_experience : 5 ) }
71+ it { expect ( hobbies [ 1 ] ) . to have_attributes ( name : 'Web ' , level : 2 , years_experience : 5 ) }
12672 end
12773
12874 context 'with array of strings' do
12975 subject { user_param . tags }
13076
131- it { is_expected . to eq ( %w[ Ruby Rails 技術書 ] ) }
77+ it { is_expected . to eq ( %w[ Ruby Rails Web ] ) }
13278 end
13379 end
13480
13581 context 'with ActionController::Parameters' do
136- subject ( :user_param ) { user_parameter_class . new ( action_controller_params ) }
82+ subject ( :user_param ) { UserParameter . new ( action_controller_params ) }
13783
13884 let ( :action_controller_params ) do
13985 ActionController ::Parameters . new ( valid_params . merge ( unpermitted : 'value' ) )
@@ -147,50 +93,24 @@ def self.name
14793
14894 context 'with invalid parameter type' do
14995 it 'raises ArgumentError' do
150- expect { user_parameter_class . new ( 'invalid' ) } . to raise_error ( ArgumentError )
96+ expect { UserParameter . new ( 'invalid' ) } . to raise_error ( ArgumentError )
15197 end
15298 end
15399 end
154100
155101 describe '#valid?' do
156102 context 'with valid object parameters' do
157- subject ( :user_param ) { user_parameter_class . new ( valid_params ) }
158-
159- let ( :valid_params ) do
160- {
161- name : 'Tanaka Taro' ,
162- email : 'tanaka@example.com' ,
163- age : 30 ,
164- address : {
165- postal_code : '123-4567' ,
166- prefecture : 'Tokyo' ,
167- city : 'Shibuya-ku' ,
168- street : 'Saka 1-2-3'
169- } ,
170- hobbies : [
171- { name : 'programming' , level : 3 , years_experience : 10 }
172- ]
173- }
174- end
103+ subject ( :user_param ) { build ( :user_parameter ) }
175104
176105 it { is_expected . to be_valid }
177106 end
178107
179108 context 'with invalid parent parameters' do
180- subject ( :user_param ) { user_parameter_class . new ( invalid_parent_params ) }
181-
182- let ( :invalid_parent_params ) do
183- {
184- name : '' , # invalid
185- email : 'invalid-email' , # invalid
186- age : -1 , # invalid
187- address : {
188- postal_code : '123-4567' ,
189- prefecture : 'Tokyo' ,
190- city : 'Shibuya-ku' ,
191- street : 'Saka 1-2-3'
192- }
193- }
109+ subject ( :user_param ) do
110+ build ( :user_parameter ,
111+ name : '' ,
112+ email : 'invalid-email' ,
113+ age : -1 )
194114 end
195115
196116 it 'returns false and includes parent validation errors' do
@@ -202,20 +122,15 @@ def self.name
202122 end
203123
204124 context 'with invalid object single object' do
205- subject ( :user_param ) { user_parameter_class . new ( invalid_address_params ) }
206-
207- let ( :invalid_address_params ) do
208- {
209- name : '' , # invalid
210- email : 'tanaka@example.com' ,
211- age : 30 ,
212- address : {
213- postal_code : 'invalid' , # invalid format
214- prefecture : '' , # blank
215- city : 'Shibuya-ku' ,
216- street : 'Saka 1-2-3'
217- }
218- }
125+ subject ( :user_param ) do
126+ build ( :user_parameter ,
127+ name : '' , # blank
128+ address : {
129+ postal_code : 'invalid' , # invalid format
130+ prefecture : '' , # blank
131+ city : 'Shibuya-ku' ,
132+ street : 'Saka 1-2-3'
133+ } )
219134 end
220135
221136 it 'returns false and includes object validation errors' do
@@ -227,94 +142,46 @@ def self.name
227142 end
228143
229144 context 'with invalid object array objects' do
230- subject ( :user_param ) { user_parameter_class . new ( invalid_hobbies_params ) }
231-
232- let ( :invalid_hobbies_params ) do
233- {
234- name : 'Tanaka Taro' ,
235- email : 'tanaka@example.com' ,
236- age : 30 ,
237- hobbies : [
238- { name : '' , level : 5 , years_experience : -1 } , # all invalid
239- { name : 'valid hobby' , level : 2 , years_experience : 3 } # valid
240- ]
241- }
145+ subject ( :user_param ) do
146+ build ( :user_parameter ,
147+ hobbies : [
148+ { name : '' , level : 5 , years_experience : -1 } , # all invalid
149+ { name : 'valid hobby' , level : 2 , years_experience : 3 } # valid
150+ ] )
242151 end
243152
244153 it 'returns false and includes array validation errors with index' do
245154 expect ( user_param ) . not_to be_valid
246- expect ( user_param . errors [ 'hobbies.0.name' ] ) . to include ( "can't be blank" )
247- expect ( user_param . errors [ 'hobbies.0.level' ] ) . to include ( 'is not included in the list' )
248- expect ( user_param . errors [ 'hobbies.0.years_experience' ] ) . to include ( 'must be greater than or equal to 0' )
155+ expect ( user_param . errors [ : 'hobbies.0.name'] ) . to include ( "can't be blank" )
156+ expect ( user_param . errors [ : 'hobbies.0.level'] ) . to include ( 'is not included in the list' )
157+ expect ( user_param . errors [ : 'hobbies.0.years_experience'] ) . to include ( 'must be greater than or equal to 0' )
249158 end
250159 end
251160 end
252161
253162 describe '#attributes' do
254- subject ( :attributes ) { user_parameter_class . new ( params ) . attributes ( symbolize : symbolize ) }
163+ subject ( :attributes ) { build ( :user_parameter , ** user_param_attributes ) . attributes ( symbolize : symbolize ) }
255164
256- let ( :symbolize ) { false }
165+ let ( :user_param_attributes ) { attributes_for ( :user_parameter ) }
257166
258- let ( :params ) do
259- {
260- name : 'Tanaka Taro' ,
261- email : 'tanaka@example.com' ,
262- age : 30 ,
263- address : {
264- postal_code : '123-4567' ,
265- prefecture : 'Tokyo' ,
266- city : 'Shibuya-ku' ,
267- street : 'Saka 1-2-3'
268- } ,
269- hobbies : [
270- { name : 'programming' , level : 3 , years_experience : 10 }
271- ] ,
272- tags : %w[ Ruby Rails ]
273- }
274- end
167+ context 'when symbolize: false' do
168+ let ( :symbolize ) { false }
275169
276- it 'returns attributes with objects converted to hashes' do
277- expect ( attributes ) . to include (
278- 'name' => 'Tanaka Taro' ,
279- 'address' => hash_including (
280- 'postal_code' => '123-4567' ,
281- 'prefecture' => 'Tokyo' ,
282- 'city' => 'Shibuya-ku' ,
283- 'street' => 'Saka 1-2-3'
284- ) ,
285- 'hobbies' => array_including (
286- hash_including ( 'name' => 'programming' , 'level' => 3 , 'years_experience' => 10 )
287- ) ,
288- 'tags' => %w[ Ruby Rails ]
289- )
170+ it { is_expected . to eq user_param_attributes . deep_stringify_keys }
290171 end
291172
292173 context 'with symbolize: true' do
293174 let ( :symbolize ) { true }
294175
295- it 'returns symbolized attributes' do
296- expect ( attributes ) . to include (
297- name : 'Tanaka Taro' ,
298- address : hash_including (
299- postal_code : '123-4567' ,
300- prefecture : 'Tokyo' ,
301- city : 'Shibuya-ku' ,
302- street : 'Saka 1-2-3'
303- ) ,
304- hobbies : array_including (
305- hash_including ( name : 'programming' , level : 3 , years_experience : 10 )
306- ) ,
307- tags : %w[ Ruby Rails ]
308- )
309- end
176+ it { is_expected . to eq user_param_attributes . deep_symbolize_keys }
310177 end
311178 end
312179
313180 describe 'edge cases' do
314- context 'with nil object values' do
315- subject ( :user_param ) { user_parameter_class . new ( params_with_nil ) }
181+ subject ( :user_param ) { build ( :user_parameter , **params ) }
316182
317- let ( :params_with_nil ) do
183+ context 'with nil object values' do
184+ let ( :params ) do
318185 {
319186 name : 'Tanaka Taro' ,
320187 email : 'tanaka@example.com' ,
@@ -335,9 +202,7 @@ def self.name
335202 end
336203
337204 context 'with empty arrays' do
338- subject ( :user_param ) { user_parameter_class . new ( params_with_empty_arrays ) }
339-
340- let ( :params_with_empty_arrays ) do
205+ let ( :params ) do
341206 {
342207 name : 'Tanaka Taro' ,
343208 email : 'tanaka@example.com' ,
0 commit comments