grape 1.5.2 → 1.7.0

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.
Files changed (210) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +75 -0
  3. data/CONTRIBUTING.md +2 -1
  4. data/README.md +152 -21
  5. data/UPGRADING.md +86 -2
  6. data/grape.gemspec +5 -5
  7. data/lib/grape/api/instance.rb +14 -18
  8. data/lib/grape/api.rb +18 -13
  9. data/lib/grape/cookies.rb +2 -0
  10. data/lib/grape/dry_types.rb +12 -0
  11. data/lib/grape/dsl/api.rb +0 -2
  12. data/lib/grape/dsl/callbacks.rb +0 -2
  13. data/lib/grape/dsl/configuration.rb +0 -2
  14. data/lib/grape/dsl/desc.rb +2 -19
  15. data/lib/grape/dsl/headers.rb +5 -2
  16. data/lib/grape/dsl/helpers.rb +7 -7
  17. data/lib/grape/dsl/inside_route.rb +43 -30
  18. data/lib/grape/dsl/middleware.rb +4 -6
  19. data/lib/grape/dsl/parameters.rb +8 -10
  20. data/lib/grape/dsl/request_response.rb +9 -8
  21. data/lib/grape/dsl/routing.rb +6 -4
  22. data/lib/grape/dsl/settings.rb +5 -7
  23. data/lib/grape/dsl/validations.rb +0 -15
  24. data/lib/grape/endpoint.rb +21 -36
  25. data/lib/grape/error_formatter/json.rb +9 -7
  26. data/lib/grape/error_formatter/xml.rb +2 -6
  27. data/lib/grape/exceptions/base.rb +2 -2
  28. data/lib/grape/exceptions/empty_message_body.rb +11 -0
  29. data/lib/grape/exceptions/missing_group_type.rb +8 -1
  30. data/lib/grape/exceptions/too_many_multipart_files.rb +11 -0
  31. data/lib/grape/exceptions/unsupported_group_type.rb +8 -1
  32. data/lib/grape/exceptions/validation.rb +1 -6
  33. data/lib/grape/formatter/json.rb +1 -0
  34. data/lib/grape/formatter/serializable_hash.rb +2 -1
  35. data/lib/grape/formatter/xml.rb +1 -0
  36. data/lib/grape/locale/en.yml +9 -8
  37. data/lib/grape/middleware/auth/dsl.rb +7 -2
  38. data/lib/grape/middleware/base.rb +3 -1
  39. data/lib/grape/middleware/error.rb +2 -2
  40. data/lib/grape/middleware/formatter.rb +4 -4
  41. data/lib/grape/middleware/stack.rb +2 -2
  42. data/lib/grape/middleware/versioner/accept_version_header.rb +3 -5
  43. data/lib/grape/middleware/versioner/header.rb +6 -4
  44. data/lib/grape/middleware/versioner/param.rb +1 -0
  45. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
  46. data/lib/grape/middleware/versioner/path.rb +2 -0
  47. data/lib/grape/parser/json.rb +1 -1
  48. data/lib/grape/parser/xml.rb +1 -1
  49. data/lib/grape/path.rb +1 -0
  50. data/lib/grape/request.rb +5 -0
  51. data/lib/grape/router/pattern.rb +1 -1
  52. data/lib/grape/router/route.rb +2 -2
  53. data/lib/grape/router.rb +6 -0
  54. data/lib/grape/util/inheritable_setting.rb +1 -3
  55. data/lib/grape/util/json.rb +2 -0
  56. data/lib/grape/util/lazy_value.rb +3 -2
  57. data/lib/grape/util/strict_hash_configuration.rb +1 -1
  58. data/lib/grape/validations/attributes_doc.rb +58 -0
  59. data/lib/grape/validations/params_scope.rb +137 -78
  60. data/lib/grape/validations/types/array_coercer.rb +0 -2
  61. data/lib/grape/validations/types/custom_type_coercer.rb +1 -2
  62. data/lib/grape/validations/types/dry_type_coercer.rb +4 -8
  63. data/lib/grape/validations/types/json.rb +2 -1
  64. data/lib/grape/validations/types/primitive_coercer.rb +16 -8
  65. data/lib/grape/validations/types/set_coercer.rb +0 -2
  66. data/lib/grape/validations/types.rb +98 -30
  67. data/lib/grape/validations/validators/all_or_none_of_validator.rb +16 -0
  68. data/lib/grape/validations/validators/allow_blank_validator.rb +20 -0
  69. data/lib/grape/validations/validators/as_validator.rb +14 -0
  70. data/lib/grape/validations/validators/at_least_one_of_validator.rb +15 -0
  71. data/lib/grape/validations/validators/base.rb +82 -70
  72. data/lib/grape/validations/validators/coerce_validator.rb +75 -0
  73. data/lib/grape/validations/validators/default_validator.rb +51 -0
  74. data/lib/grape/validations/validators/exactly_one_of_validator.rb +17 -0
  75. data/lib/grape/validations/validators/except_values_validator.rb +24 -0
  76. data/lib/grape/validations/validators/multiple_params_base.rb +24 -20
  77. data/lib/grape/validations/validators/mutual_exclusion_validator.rb +16 -0
  78. data/lib/grape/validations/validators/presence_validator.rb +15 -0
  79. data/lib/grape/validations/validators/regexp_validator.rb +16 -0
  80. data/lib/grape/validations/validators/same_as_validator.rb +29 -0
  81. data/lib/grape/validations/validators/values_validator.rb +88 -0
  82. data/lib/grape/validations.rb +16 -6
  83. data/lib/grape/version.rb +1 -1
  84. data/lib/grape.rb +70 -29
  85. data/spec/grape/api/custom_validations_spec.rb +116 -45
  86. data/spec/grape/api/deeply_included_options_spec.rb +3 -5
  87. data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -3
  88. data/spec/grape/api/documentation_spec.rb +59 -0
  89. data/spec/grape/api/inherited_helpers_spec.rb +0 -2
  90. data/spec/grape/api/instance_spec.rb +0 -1
  91. data/spec/grape/api/invalid_format_spec.rb +2 -2
  92. data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -2
  93. data/spec/grape/api/nested_helpers_spec.rb +0 -2
  94. data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -2
  95. data/spec/grape/api/parameters_modification_spec.rb +0 -2
  96. data/spec/grape/api/patch_method_helpers_spec.rb +0 -2
  97. data/spec/grape/api/recognize_path_spec.rb +1 -3
  98. data/spec/grape/api/required_parameters_in_route_spec.rb +0 -2
  99. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -2
  100. data/spec/grape/api/routes_with_requirements_spec.rb +8 -10
  101. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -17
  102. data/spec/grape/api/shared_helpers_spec.rb +0 -2
  103. data/spec/grape/api_remount_spec.rb +16 -16
  104. data/spec/grape/api_spec.rb +527 -224
  105. data/spec/grape/config_spec.rb +0 -2
  106. data/spec/grape/dsl/callbacks_spec.rb +2 -3
  107. data/spec/grape/dsl/configuration_spec.rb +0 -2
  108. data/spec/grape/dsl/desc_spec.rb +0 -2
  109. data/spec/grape/dsl/headers_spec.rb +39 -11
  110. data/spec/grape/dsl/helpers_spec.rb +3 -4
  111. data/spec/grape/dsl/inside_route_spec.rb +16 -16
  112. data/spec/grape/dsl/logger_spec.rb +15 -19
  113. data/spec/grape/dsl/middleware_spec.rb +2 -3
  114. data/spec/grape/dsl/parameters_spec.rb +2 -2
  115. data/spec/grape/dsl/request_response_spec.rb +7 -8
  116. data/spec/grape/dsl/routing_spec.rb +11 -10
  117. data/spec/grape/dsl/settings_spec.rb +0 -2
  118. data/spec/grape/dsl/validations_spec.rb +0 -17
  119. data/spec/grape/endpoint/declared_spec.rb +261 -16
  120. data/spec/grape/endpoint_spec.rb +98 -57
  121. data/spec/grape/entity_spec.rb +22 -23
  122. data/spec/grape/exceptions/base_spec.rb +16 -2
  123. data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -2
  124. data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -24
  125. data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -2
  126. data/spec/grape/exceptions/invalid_response_spec.rb +0 -2
  127. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +1 -3
  128. data/spec/grape/exceptions/missing_group_type_spec.rb +21 -0
  129. data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -2
  130. data/spec/grape/exceptions/missing_option_spec.rb +1 -3
  131. data/spec/grape/exceptions/unknown_options_spec.rb +0 -2
  132. data/spec/grape/exceptions/unknown_validator_spec.rb +0 -2
  133. data/spec/grape/exceptions/unsupported_group_type_spec.rb +23 -0
  134. data/spec/grape/exceptions/validation_errors_spec.rb +13 -11
  135. data/spec/grape/exceptions/validation_spec.rb +5 -5
  136. data/spec/grape/extensions/param_builders/hash_spec.rb +7 -9
  137. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -10
  138. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -10
  139. data/spec/grape/integration/global_namespace_function_spec.rb +0 -2
  140. data/spec/grape/integration/rack_sendfile_spec.rb +1 -3
  141. data/spec/grape/integration/rack_spec.rb +0 -2
  142. data/spec/grape/loading_spec.rb +8 -10
  143. data/spec/grape/middleware/auth/base_spec.rb +0 -1
  144. data/spec/grape/middleware/auth/dsl_spec.rb +15 -8
  145. data/spec/grape/middleware/auth/strategies_spec.rb +60 -22
  146. data/spec/grape/middleware/base_spec.rb +24 -17
  147. data/spec/grape/middleware/error_spec.rb +8 -3
  148. data/spec/grape/middleware/exception_spec.rb +111 -163
  149. data/spec/grape/middleware/formatter_spec.rb +27 -8
  150. data/spec/grape/middleware/globals_spec.rb +7 -6
  151. data/spec/grape/middleware/stack_spec.rb +14 -14
  152. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -3
  153. data/spec/grape/middleware/versioner/header_spec.rb +30 -15
  154. data/spec/grape/middleware/versioner/param_spec.rb +7 -3
  155. data/spec/grape/middleware/versioner/path_spec.rb +5 -3
  156. data/spec/grape/middleware/versioner_spec.rb +1 -3
  157. data/spec/grape/named_api_spec.rb +0 -2
  158. data/spec/grape/parser_spec.rb +4 -2
  159. data/spec/grape/path_spec.rb +52 -54
  160. data/spec/grape/presenters/presenter_spec.rb +7 -8
  161. data/spec/grape/request_spec.rb +6 -6
  162. data/spec/grape/util/inheritable_setting_spec.rb +7 -8
  163. data/spec/grape/util/inheritable_values_spec.rb +3 -3
  164. data/spec/grape/util/reverse_stackable_values_spec.rb +3 -2
  165. data/spec/grape/util/stackable_values_spec.rb +7 -6
  166. data/spec/grape/util/strict_hash_configuration_spec.rb +0 -1
  167. data/spec/grape/validations/attributes_doc_spec.rb +153 -0
  168. data/spec/grape/validations/attributes_iterator_spec.rb +0 -2
  169. data/spec/grape/validations/instance_behaivour_spec.rb +9 -12
  170. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +1 -2
  171. data/spec/grape/validations/params_scope_spec.rb +361 -96
  172. data/spec/grape/validations/single_attribute_iterator_spec.rb +2 -3
  173. data/spec/grape/validations/types/array_coercer_spec.rb +0 -2
  174. data/spec/grape/validations/types/primitive_coercer_spec.rb +24 -9
  175. data/spec/grape/validations/types/set_coercer_spec.rb +0 -2
  176. data/spec/grape/validations/types_spec.rb +36 -10
  177. data/spec/grape/validations/validators/all_or_none_spec.rb +50 -58
  178. data/spec/grape/validations/validators/allow_blank_spec.rb +135 -141
  179. data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -58
  180. data/spec/grape/validations/validators/coerce_spec.rb +99 -24
  181. data/spec/grape/validations/validators/default_spec.rb +72 -80
  182. data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -79
  183. data/spec/grape/validations/validators/except_values_spec.rb +3 -5
  184. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -79
  185. data/spec/grape/validations/validators/presence_spec.rb +16 -3
  186. data/spec/grape/validations/validators/regexp_spec.rb +25 -33
  187. data/spec/grape/validations/validators/same_as_spec.rb +14 -22
  188. data/spec/grape/validations/validators/values_spec.rb +182 -179
  189. data/spec/grape/validations_spec.rb +149 -80
  190. data/spec/integration/eager_load/eager_load_spec.rb +2 -2
  191. data/spec/integration/multi_json/json_spec.rb +1 -3
  192. data/spec/integration/multi_xml/xml_spec.rb +1 -3
  193. data/spec/shared/versioning_examples.rb +12 -9
  194. data/spec/spec_helper.rb +21 -6
  195. data/spec/support/basic_auth_encode_helpers.rb +1 -1
  196. metadata +125 -115
  197. data/lib/grape/validations/validators/all_or_none.rb +0 -15
  198. data/lib/grape/validations/validators/allow_blank.rb +0 -18
  199. data/lib/grape/validations/validators/as.rb +0 -16
  200. data/lib/grape/validations/validators/at_least_one_of.rb +0 -14
  201. data/lib/grape/validations/validators/coerce.rb +0 -91
  202. data/lib/grape/validations/validators/default.rb +0 -48
  203. data/lib/grape/validations/validators/exactly_one_of.rb +0 -16
  204. data/lib/grape/validations/validators/except_values.rb +0 -22
  205. data/lib/grape/validations/validators/mutual_exclusion.rb +0 -15
  206. data/lib/grape/validations/validators/presence.rb +0 -12
  207. data/lib/grape/validations/validators/regexp.rb +0 -13
  208. data/lib/grape/validations/validators/same_as.rb +0 -26
  209. data/lib/grape/validations/validators/values.rb +0 -83
  210. data/spec/support/eager_load.rb +0 -19
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'spec_helper'
4
-
5
3
  describe Grape::Endpoint do
6
4
  subject { Class.new(Grape::API) }
7
5
 
@@ -87,7 +85,7 @@ describe Grape::Endpoint do
87
85
  end
88
86
  end
89
87
 
90
- it 'should show nil for nested params if include_missing is true' do
88
+ it 'shows nil for nested params if include_missing is true' do
91
89
  subject.get '/declared' do
92
90
  declared(params, include_missing: true)
93
91
  end
@@ -97,7 +95,7 @@ describe Grape::Endpoint do
97
95
  expect(JSON.parse(last_response.body)['nested']['fourth']).to be_nil
98
96
  end
99
97
 
100
- it 'should show nil for multiple allowed types if include_missing is true' do
98
+ it 'shows nil for multiple allowed types if include_missing is true' do
101
99
  subject.get '/declared' do
102
100
  declared(params, include_missing: true)
103
101
  end
@@ -249,7 +247,7 @@ describe Grape::Endpoint do
249
247
  end
250
248
  get '/declared?first=one&other=two'
251
249
  expect(last_response.status).to eq(200)
252
- expect(JSON.parse(last_response.body).key?(:other)).to eq false
250
+ expect(JSON.parse(last_response.body).key?(:other)).to be false
253
251
  end
254
252
 
255
253
  it 'stringifies if that option is passed' do
@@ -522,7 +520,7 @@ describe Grape::Endpoint do
522
520
  json = JSON.parse(last_response.body, symbolize_names: true)
523
521
 
524
522
  expect(json[:declared_params][:id]).to eq 123
525
- expect(json[:declared_params_no_parent][:id]).to eq nil
523
+ expect(json[:declared_params_no_parent][:id]).to be_nil
526
524
  end
527
525
  end
528
526
 
@@ -568,34 +566,281 @@ describe Grape::Endpoint do
568
566
  get '/artists/1'
569
567
  json = JSON.parse(last_response.body, symbolize_names: true)
570
568
 
571
- expect(json.key?(:id)).to be_truthy
572
- expect(json.key?(:artist_id)).not_to be_truthy
569
+ expect(json).to be_key(:id)
570
+ expect(json).not_to be_key(:artist_id)
573
571
  end
574
572
 
575
573
  it 'return only :artist_id without :id' do
576
574
  get '/artists/1/compositions'
577
575
  json = JSON.parse(last_response.body, symbolize_names: true)
578
576
 
579
- expect(json.key?(:artist_id)).to be_truthy
580
- expect(json.key?(:id)).not_to be_truthy
577
+ expect(json).to be_key(:artist_id)
578
+ expect(json).not_to be_key(:id)
581
579
  end
582
580
 
583
581
  it 'return :filter and :id parameters in declared for second enpoint inside route_param' do
584
582
  get '/artists/1/some_route', filter: 'some_filter'
585
583
  json = JSON.parse(last_response.body, symbolize_names: true)
586
584
 
587
- expect(json.key?(:filter)).to be_truthy
588
- expect(json.key?(:id)).to be_truthy
589
- expect(json.key?(:artist_id)).not_to be_truthy
585
+ expect(json).to be_key(:filter)
586
+ expect(json).to be_key(:id)
587
+ expect(json).not_to be_key(:artist_id)
590
588
  end
591
589
 
592
590
  it 'return :compositor_id for mounter in route_param' do
593
591
  get '/artists/1/albums'
594
592
  json = JSON.parse(last_response.body, symbolize_names: true)
595
593
 
596
- expect(json.key?(:compositor_id)).to be_truthy
597
- expect(json.key?(:id)).not_to be_truthy
598
- expect(json.key?(:artist_id)).not_to be_truthy
594
+ expect(json).to be_key(:compositor_id)
595
+ expect(json).not_to be_key(:id)
596
+ expect(json).not_to be_key(:artist_id)
597
+ end
598
+ end
599
+
600
+ describe 'parameter renaming' do
601
+ context 'with a deeply nested parameter structure' do
602
+ let(:params) do
603
+ {
604
+ i_a: 'a',
605
+ i_b: {
606
+ i_c: 'c',
607
+ i_d: {
608
+ i_e: {
609
+ i_f: 'f',
610
+ i_g: 'g',
611
+ i_h: [
612
+ {
613
+ i_ha: 'ha1',
614
+ i_hb: {
615
+ i_hc: 'c'
616
+ }
617
+ },
618
+ {
619
+ i_ha: 'ha2',
620
+ i_hb: {
621
+ i_hc: 'c'
622
+ }
623
+ }
624
+ ]
625
+ }
626
+ }
627
+ }
628
+ }
629
+ end
630
+ let(:declared) do
631
+ {
632
+ o_a: 'a',
633
+ o_b: {
634
+ o_c: 'c',
635
+ o_d: {
636
+ o_e: {
637
+ o_f: 'f',
638
+ o_g: 'g',
639
+ o_h: [
640
+ {
641
+ o_ha: 'ha1',
642
+ o_hb: {
643
+ o_hc: 'c'
644
+ }
645
+ },
646
+ {
647
+ o_ha: 'ha2',
648
+ o_hb: {
649
+ o_hc: 'c'
650
+ }
651
+ }
652
+ ]
653
+ }
654
+ }
655
+ }
656
+ }
657
+ end
658
+ let(:params_keys) do
659
+ [
660
+ 'i_a',
661
+ 'i_b',
662
+ 'i_b[i_c]',
663
+ 'i_b[i_d]',
664
+ 'i_b[i_d][i_e]',
665
+ 'i_b[i_d][i_e][i_f]',
666
+ 'i_b[i_d][i_e][i_g]',
667
+ 'i_b[i_d][i_e][i_h]',
668
+ 'i_b[i_d][i_e][i_h][i_ha]',
669
+ 'i_b[i_d][i_e][i_h][i_hb]',
670
+ 'i_b[i_d][i_e][i_h][i_hb][i_hc]'
671
+ ]
672
+ end
673
+
674
+ before do
675
+ subject.format :json
676
+ subject.params do
677
+ optional :i_a, type: String, as: :o_a
678
+ optional :i_b, type: Hash, as: :o_b do
679
+ optional :i_c, type: String, as: :o_c
680
+ optional :i_d, type: Hash, as: :o_d do
681
+ optional :i_e, type: Hash, as: :o_e do
682
+ optional :i_f, type: String, as: :o_f
683
+ optional :i_g, type: String, as: :o_g
684
+ optional :i_h, type: Array, as: :o_h do
685
+ optional :i_ha, type: String, as: :o_ha
686
+ optional :i_hb, type: Hash, as: :o_hb do
687
+ optional :i_hc, type: String, as: :o_hc
688
+ end
689
+ end
690
+ end
691
+ end
692
+ end
693
+ end
694
+ subject.post '/test' do
695
+ declared(params, include_missing: false)
696
+ end
697
+ subject.post '/test/no-mod' do
698
+ before = params.to_h
699
+ declared(params, include_missing: false)
700
+ after = params.to_h
701
+ { before: before, after: after }
702
+ end
703
+ end
704
+
705
+ it 'generates the correct parameter names for documentation' do
706
+ expect(subject.routes.first.params.keys).to match(params_keys)
707
+ end
708
+
709
+ it 'maps the renamed parameter correctly' do
710
+ post '/test', **params
711
+ expect(JSON.parse(last_response.body, symbolize_names: true)).to \
712
+ match(declared)
713
+ end
714
+
715
+ it 'maps no parameters when none are given' do
716
+ post '/test'
717
+ expect(JSON.parse(last_response.body)).to match({})
718
+ end
719
+
720
+ it 'does not modify the request params' do
721
+ post '/test/no-mod', **params
722
+ result = JSON.parse(last_response.body, symbolize_names: true)
723
+ expect(result[:before]).to match(result[:after])
724
+ end
725
+ end
726
+
727
+ context 'with a renamed root parameter' do
728
+ before do
729
+ subject.format :json
730
+ subject.params do
731
+ optional :email_address, type: String, regexp: /.+@.+/, as: :email
732
+ end
733
+ subject.post '/test' do
734
+ declared(params, include_missing: false)
735
+ end
736
+ end
737
+
738
+ it 'generates the correct parameter names for documentation' do
739
+ expect(subject.routes.first.params.keys).to match(%w[email_address])
740
+ end
741
+
742
+ it 'maps the renamed parameter correctly (original name)' do
743
+ post '/test', email_address: 'test@example.com'
744
+ expect(JSON.parse(last_response.body)).to \
745
+ match('email' => 'test@example.com')
746
+ end
747
+
748
+ it 'validates the renamed parameter correctly (original name)' do
749
+ post '/test', email_address: 'bad[at]example.com'
750
+ expect(JSON.parse(last_response.body)).to \
751
+ match('error' => 'email_address is invalid')
752
+ end
753
+
754
+ it 'ignores the renamed parameter (as name)' do
755
+ post '/test', email: 'test@example.com'
756
+ expect(JSON.parse(last_response.body)).to match({})
757
+ end
758
+ end
759
+
760
+ context 'with a renamed hash with nested parameters' do
761
+ before do
762
+ subject.format :json
763
+ subject.params do
764
+ optional :address, type: Hash, as: :address_attributes do
765
+ optional :street, type: String, values: ['Street 1', 'Street 2'],
766
+ default: 'Street 1'
767
+ optional :city, type: String
768
+ end
769
+ end
770
+ subject.post '/test' do
771
+ declared(params, include_missing: false)
772
+ end
773
+ end
774
+
775
+ it 'generates the correct parameter names for documentation' do
776
+ expect(subject.routes.first.params.keys).to \
777
+ match(%w[address address[street] address[city]])
778
+ end
779
+
780
+ it 'maps the renamed parameter correctly (original name)' do
781
+ post '/test', address: { city: 'Berlin', street: 'Street 2', t: 't' }
782
+ expect(JSON.parse(last_response.body)).to \
783
+ match('address_attributes' => { 'city' => 'Berlin',
784
+ 'street' => 'Street 2' })
785
+ end
786
+
787
+ it 'validates the renamed parameter correctly (original name)' do
788
+ post '/test', address: { street: 'unknown' }
789
+ expect(JSON.parse(last_response.body)).to \
790
+ match('error' => 'address[street] does not have a valid value')
791
+ end
792
+
793
+ it 'ignores the renamed parameter (as name)' do
794
+ post '/test', address_attributes: { city: 'Berlin', unknown: '1' }
795
+ expect(JSON.parse(last_response.body)).to match({})
796
+ end
797
+ end
798
+
799
+ context 'with a renamed hash with nested renamed parameter' do
800
+ before do
801
+ subject.format :json
802
+ subject.params do
803
+ optional :user, type: Hash, as: :user_attributes do
804
+ optional :email_address, type: String, regexp: /.+@.+/, as: :email
805
+ end
806
+ end
807
+ subject.post '/test' do
808
+ declared(params, include_missing: false)
809
+ end
810
+ end
811
+
812
+ it 'generates the correct parameter names for documentation' do
813
+ expect(subject.routes.first.params.keys).to \
814
+ match(%w[user user[email_address]])
815
+ end
816
+
817
+ it 'maps the renamed parameter correctly (original name)' do
818
+ post '/test', user: { email_address: 'test@example.com' }
819
+ expect(JSON.parse(last_response.body)).to \
820
+ match('user_attributes' => { 'email' => 'test@example.com' })
821
+ end
822
+
823
+ it 'validates the renamed parameter correctly (original name)' do
824
+ post '/test', user: { email_address: 'bad[at]example.com' }
825
+ expect(JSON.parse(last_response.body)).to \
826
+ match('error' => 'user[email_address] is invalid')
827
+ end
828
+
829
+ it 'ignores the renamed parameter (as name, 1)' do
830
+ post '/test', user: { email: 'test@example.com' }
831
+ expect(JSON.parse(last_response.body)).to \
832
+ match({ 'user_attributes' => {} })
833
+ end
834
+
835
+ it 'ignores the renamed parameter (as name, 2)' do
836
+ post '/test', user_attributes: { email_address: 'test@example.com' }
837
+ expect(JSON.parse(last_response.body)).to match({})
838
+ end
839
+
840
+ it 'ignores the renamed parameter (as name, 3)' do
841
+ post '/test', user_attributes: { email: 'test@example.com' }
842
+ expect(JSON.parse(last_response.body)).to match({})
843
+ end
599
844
  end
600
845
  end
601
846
  end