actionpack 3.2.19 → 4.0.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 (263) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +850 -401
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -288
  5. data/lib/abstract_controller/asset_paths.rb +2 -2
  6. data/lib/abstract_controller/base.rb +39 -37
  7. data/lib/abstract_controller/callbacks.rb +101 -82
  8. data/lib/abstract_controller/collector.rb +7 -3
  9. data/lib/abstract_controller/helpers.rb +25 -13
  10. data/lib/abstract_controller/layouts.rb +74 -74
  11. data/lib/abstract_controller/logger.rb +1 -2
  12. data/lib/abstract_controller/rendering.rb +30 -13
  13. data/lib/abstract_controller/translation.rb +16 -1
  14. data/lib/abstract_controller/url_for.rb +6 -6
  15. data/lib/abstract_controller/view_paths.rb +1 -1
  16. data/lib/abstract_controller.rb +1 -8
  17. data/lib/action_controller/base.rb +46 -22
  18. data/lib/action_controller/caching/fragments.rb +23 -53
  19. data/lib/action_controller/caching.rb +46 -33
  20. data/lib/action_controller/deprecated/integration_test.rb +3 -0
  21. data/lib/action_controller/deprecated.rb +5 -1
  22. data/lib/action_controller/log_subscriber.rb +16 -8
  23. data/lib/action_controller/metal/conditional_get.rb +76 -32
  24. data/lib/action_controller/metal/data_streaming.rb +20 -26
  25. data/lib/action_controller/metal/exceptions.rb +19 -6
  26. data/lib/action_controller/metal/flash.rb +24 -9
  27. data/lib/action_controller/metal/force_ssl.rb +70 -12
  28. data/lib/action_controller/metal/head.rb +25 -4
  29. data/lib/action_controller/metal/helpers.rb +5 -9
  30. data/lib/action_controller/metal/hide_actions.rb +0 -1
  31. data/lib/action_controller/metal/http_authentication.rb +107 -83
  32. data/lib/action_controller/metal/implicit_render.rb +1 -1
  33. data/lib/action_controller/metal/instrumentation.rb +2 -1
  34. data/lib/action_controller/metal/live.rb +175 -0
  35. data/lib/action_controller/metal/mime_responds.rb +161 -47
  36. data/lib/action_controller/metal/params_wrapper.rb +112 -74
  37. data/lib/action_controller/metal/rack_delegation.rb +9 -3
  38. data/lib/action_controller/metal/redirecting.rb +15 -20
  39. data/lib/action_controller/metal/renderers.rb +11 -9
  40. data/lib/action_controller/metal/rendering.rb +9 -1
  41. data/lib/action_controller/metal/request_forgery_protection.rb +112 -19
  42. data/lib/action_controller/metal/responder.rb +20 -19
  43. data/lib/action_controller/metal/streaming.rb +12 -18
  44. data/lib/action_controller/metal/strong_parameters.rb +520 -0
  45. data/lib/action_controller/metal/testing.rb +13 -18
  46. data/lib/action_controller/metal/url_for.rb +28 -25
  47. data/lib/action_controller/metal.rb +17 -32
  48. data/lib/action_controller/model_naming.rb +12 -0
  49. data/lib/action_controller/railtie.rb +33 -17
  50. data/lib/action_controller/railties/helpers.rb +22 -0
  51. data/lib/action_controller/record_identifier.rb +18 -72
  52. data/lib/action_controller/test_case.rb +251 -131
  53. data/lib/action_controller/vendor/html-scanner.rb +4 -19
  54. data/lib/action_controller.rb +15 -6
  55. data/lib/action_dispatch/http/cache.rb +63 -11
  56. data/lib/action_dispatch/http/filter_parameters.rb +18 -8
  57. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  58. data/lib/action_dispatch/http/headers.rb +49 -17
  59. data/lib/action_dispatch/http/mime_negotiation.rb +24 -1
  60. data/lib/action_dispatch/http/mime_type.rb +154 -100
  61. data/lib/action_dispatch/http/mime_types.rb +1 -1
  62. data/lib/action_dispatch/http/parameter_filter.rb +44 -46
  63. data/lib/action_dispatch/http/parameters.rb +28 -28
  64. data/lib/action_dispatch/http/rack_cache.rb +2 -3
  65. data/lib/action_dispatch/http/request.rb +64 -18
  66. data/lib/action_dispatch/http/response.rb +130 -35
  67. data/lib/action_dispatch/http/upload.rb +63 -20
  68. data/lib/action_dispatch/http/url.rb +98 -35
  69. data/lib/action_dispatch/journey/backwards.rb +5 -0
  70. data/lib/action_dispatch/journey/formatter.rb +146 -0
  71. data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
  72. data/lib/action_dispatch/journey/gtg/simulator.rb +44 -0
  73. data/lib/action_dispatch/journey/gtg/transition_table.rb +156 -0
  74. data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
  75. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  76. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  77. data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
  78. data/lib/action_dispatch/journey/nodes/node.rb +124 -0
  79. data/lib/action_dispatch/journey/parser.rb +206 -0
  80. data/lib/action_dispatch/journey/parser.y +47 -0
  81. data/lib/action_dispatch/journey/parser_extras.rb +23 -0
  82. data/lib/action_dispatch/journey/path/pattern.rb +196 -0
  83. data/lib/action_dispatch/journey/route.rb +124 -0
  84. data/lib/action_dispatch/journey/router/strexp.rb +24 -0
  85. data/lib/action_dispatch/journey/router/utils.rb +54 -0
  86. data/lib/action_dispatch/journey/router.rb +166 -0
  87. data/lib/action_dispatch/journey/routes.rb +75 -0
  88. data/lib/action_dispatch/journey/scanner.rb +61 -0
  89. data/lib/action_dispatch/journey/visitors.rb +197 -0
  90. data/lib/action_dispatch/journey/visualizer/fsm.css +34 -0
  91. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  92. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  93. data/lib/action_dispatch/journey.rb +5 -0
  94. data/lib/action_dispatch/middleware/callbacks.rb +9 -4
  95. data/lib/action_dispatch/middleware/cookies.rb +259 -114
  96. data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -17
  97. data/lib/action_dispatch/middleware/exception_wrapper.rb +29 -3
  98. data/lib/action_dispatch/middleware/flash.rb +58 -58
  99. data/lib/action_dispatch/middleware/params_parser.rb +14 -29
  100. data/lib/action_dispatch/middleware/public_exceptions.rb +30 -14
  101. data/lib/action_dispatch/middleware/reloader.rb +6 -6
  102. data/lib/action_dispatch/middleware/remote_ip.rb +145 -39
  103. data/lib/action_dispatch/middleware/request_id.rb +2 -6
  104. data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
  105. data/lib/action_dispatch/middleware/session/cookie_store.rb +82 -28
  106. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
  107. data/lib/action_dispatch/middleware/show_exceptions.rb +12 -45
  108. data/lib/action_dispatch/middleware/ssl.rb +70 -0
  109. data/lib/action_dispatch/middleware/stack.rb +6 -1
  110. data/lib/action_dispatch/middleware/static.rb +2 -1
  111. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +14 -11
  112. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +25 -0
  113. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +7 -9
  114. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +15 -9
  115. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +127 -5
  116. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +7 -2
  117. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +30 -15
  118. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +39 -13
  119. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +6 -2
  120. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  121. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +144 -0
  122. data/lib/action_dispatch/railtie.rb +16 -6
  123. data/lib/action_dispatch/request/session.rb +181 -0
  124. data/lib/action_dispatch/routing/inspector.rb +240 -0
  125. data/lib/action_dispatch/routing/mapper.rb +540 -291
  126. data/lib/action_dispatch/routing/polymorphic_routes.rb +16 -20
  127. data/lib/action_dispatch/routing/redirection.rb +46 -29
  128. data/lib/action_dispatch/routing/route_set.rb +207 -164
  129. data/lib/action_dispatch/routing/routes_proxy.rb +2 -0
  130. data/lib/action_dispatch/routing/url_for.rb +48 -33
  131. data/lib/action_dispatch/routing.rb +48 -83
  132. data/lib/action_dispatch/testing/assertions/dom.rb +3 -13
  133. data/lib/action_dispatch/testing/assertions/response.rb +32 -40
  134. data/lib/action_dispatch/testing/assertions/routing.rb +42 -41
  135. data/lib/action_dispatch/testing/assertions/selector.rb +17 -22
  136. data/lib/action_dispatch/testing/assertions/tag.rb +20 -23
  137. data/lib/action_dispatch/testing/integration.rb +65 -51
  138. data/lib/action_dispatch/testing/test_process.rb +9 -6
  139. data/lib/action_dispatch/testing/test_request.rb +7 -3
  140. data/lib/action_dispatch.rb +21 -15
  141. data/lib/action_pack/version.rb +7 -6
  142. data/lib/action_pack.rb +1 -1
  143. data/lib/action_view/base.rb +15 -34
  144. data/lib/action_view/buffers.rb +7 -1
  145. data/lib/action_view/context.rb +4 -4
  146. data/lib/action_view/dependency_tracker.rb +93 -0
  147. data/lib/action_view/digestor.rb +85 -0
  148. data/lib/action_view/flows.rb +1 -4
  149. data/lib/action_view/helpers/active_model_helper.rb +3 -4
  150. data/lib/action_view/helpers/asset_tag_helper.rb +215 -352
  151. data/lib/action_view/helpers/asset_url_helper.rb +355 -0
  152. data/lib/action_view/helpers/atom_feed_helper.rb +13 -10
  153. data/lib/action_view/helpers/cache_helper.rb +150 -18
  154. data/lib/action_view/helpers/capture_helper.rb +44 -31
  155. data/lib/action_view/helpers/csrf_helper.rb +0 -2
  156. data/lib/action_view/helpers/date_helper.rb +269 -248
  157. data/lib/action_view/helpers/debug_helper.rb +10 -11
  158. data/lib/action_view/helpers/form_helper.rb +931 -537
  159. data/lib/action_view/helpers/form_options_helper.rb +341 -166
  160. data/lib/action_view/helpers/form_tag_helper.rb +190 -90
  161. data/lib/action_view/helpers/javascript_helper.rb +23 -16
  162. data/lib/action_view/helpers/number_helper.rb +148 -329
  163. data/lib/action_view/helpers/output_safety_helper.rb +3 -3
  164. data/lib/action_view/helpers/record_tag_helper.rb +17 -22
  165. data/lib/action_view/helpers/rendering_helper.rb +2 -2
  166. data/lib/action_view/helpers/sanitize_helper.rb +3 -6
  167. data/lib/action_view/helpers/tag_helper.rb +46 -33
  168. data/lib/action_view/helpers/tags/base.rb +147 -0
  169. data/lib/action_view/helpers/tags/check_box.rb +64 -0
  170. data/lib/action_view/helpers/tags/checkable.rb +16 -0
  171. data/lib/action_view/helpers/tags/collection_check_boxes.rb +43 -0
  172. data/lib/action_view/helpers/tags/collection_helpers.rb +83 -0
  173. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +36 -0
  174. data/lib/action_view/helpers/tags/collection_select.rb +28 -0
  175. data/lib/action_view/helpers/tags/color_field.rb +25 -0
  176. data/lib/action_view/helpers/tags/date_field.rb +13 -0
  177. data/lib/action_view/helpers/tags/date_select.rb +72 -0
  178. data/lib/action_view/helpers/tags/datetime_field.rb +22 -0
  179. data/lib/action_view/helpers/tags/datetime_local_field.rb +19 -0
  180. data/lib/action_view/helpers/tags/datetime_select.rb +8 -0
  181. data/lib/action_view/helpers/tags/email_field.rb +8 -0
  182. data/lib/action_view/helpers/tags/file_field.rb +8 -0
  183. data/lib/action_view/helpers/tags/grouped_collection_select.rb +29 -0
  184. data/lib/action_view/helpers/tags/hidden_field.rb +8 -0
  185. data/lib/action_view/helpers/tags/label.rb +65 -0
  186. data/lib/action_view/helpers/tags/month_field.rb +13 -0
  187. data/lib/action_view/helpers/tags/number_field.rb +18 -0
  188. data/lib/action_view/helpers/tags/password_field.rb +12 -0
  189. data/lib/action_view/helpers/tags/radio_button.rb +31 -0
  190. data/lib/action_view/helpers/tags/range_field.rb +8 -0
  191. data/lib/action_view/helpers/tags/search_field.rb +24 -0
  192. data/lib/action_view/helpers/tags/select.rb +40 -0
  193. data/lib/action_view/helpers/tags/tel_field.rb +8 -0
  194. data/lib/action_view/helpers/tags/text_area.rb +18 -0
  195. data/lib/action_view/helpers/tags/text_field.rb +29 -0
  196. data/lib/action_view/helpers/tags/time_field.rb +13 -0
  197. data/lib/action_view/helpers/tags/time_select.rb +8 -0
  198. data/lib/action_view/helpers/tags/time_zone_select.rb +20 -0
  199. data/lib/action_view/helpers/tags/url_field.rb +8 -0
  200. data/lib/action_view/helpers/tags/week_field.rb +13 -0
  201. data/lib/action_view/helpers/tags.rb +39 -0
  202. data/lib/action_view/helpers/text_helper.rb +130 -114
  203. data/lib/action_view/helpers/translation_helper.rb +32 -16
  204. data/lib/action_view/helpers/url_helper.rb +211 -270
  205. data/lib/action_view/helpers.rb +2 -4
  206. data/lib/action_view/locale/en.yml +1 -105
  207. data/lib/action_view/log_subscriber.rb +6 -4
  208. data/lib/action_view/lookup_context.rb +15 -28
  209. data/lib/action_view/model_naming.rb +12 -0
  210. data/lib/action_view/path_set.rb +8 -20
  211. data/lib/action_view/railtie.rb +6 -22
  212. data/lib/action_view/record_identifier.rb +84 -0
  213. data/lib/action_view/renderer/abstract_renderer.rb +25 -19
  214. data/lib/action_view/renderer/partial_renderer.rb +158 -81
  215. data/lib/action_view/renderer/renderer.rb +8 -12
  216. data/lib/action_view/renderer/streaming_template_renderer.rb +2 -5
  217. data/lib/action_view/renderer/template_renderer.rb +12 -10
  218. data/lib/action_view/routing_url_for.rb +107 -0
  219. data/lib/action_view/template/error.rb +22 -12
  220. data/lib/action_view/template/handlers/builder.rb +1 -1
  221. data/lib/action_view/template/handlers/erb.rb +40 -19
  222. data/lib/action_view/template/handlers/raw.rb +11 -0
  223. data/lib/action_view/template/handlers.rb +12 -9
  224. data/lib/action_view/template/resolver.rb +107 -53
  225. data/lib/action_view/template/text.rb +12 -8
  226. data/lib/action_view/template/types.rb +57 -0
  227. data/lib/action_view/template.rb +25 -23
  228. data/lib/action_view/test_case.rb +67 -42
  229. data/lib/{action_controller → action_view}/vendor/html-scanner/html/document.rb +0 -0
  230. data/lib/{action_controller → action_view}/vendor/html-scanner/html/node.rb +12 -12
  231. data/lib/{action_controller → action_view}/vendor/html-scanner/html/sanitizer.rb +13 -2
  232. data/lib/{action_controller → action_view}/vendor/html-scanner/html/selector.rb +9 -9
  233. data/lib/{action_controller → action_view}/vendor/html-scanner/html/tokenizer.rb +1 -1
  234. data/lib/{action_controller → action_view}/vendor/html-scanner/html/version.rb +0 -0
  235. data/lib/action_view/vendor/html-scanner.rb +20 -0
  236. data/lib/action_view.rb +17 -8
  237. metadata +184 -214
  238. data/lib/action_controller/caching/actions.rb +0 -185
  239. data/lib/action_controller/caching/pages.rb +0 -187
  240. data/lib/action_controller/caching/sweeping.rb +0 -97
  241. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  242. data/lib/action_controller/metal/compatibility.rb +0 -65
  243. data/lib/action_controller/metal/session_management.rb +0 -14
  244. data/lib/action_controller/railties/paths.rb +0 -25
  245. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  246. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  247. data/lib/action_dispatch/middleware/head.rb +0 -18
  248. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  249. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  250. data/lib/action_view/asset_paths.rb +0 -142
  251. data/lib/action_view/helpers/asset_paths.rb +0 -7
  252. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  253. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  254. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  255. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  256. data/lib/sprockets/assets.rake +0 -99
  257. data/lib/sprockets/bootstrap.rb +0 -37
  258. data/lib/sprockets/compressors.rb +0 -83
  259. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  260. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  261. data/lib/sprockets/helpers.rb +0 -6
  262. data/lib/sprockets/railtie.rb +0 -62
  263. data/lib/sprockets/static_compiler.rb +0 -56
@@ -0,0 +1,520 @@
1
+ require 'active_support/core_ext/hash/indifferent_access'
2
+ require 'active_support/core_ext/array/wrap'
3
+ require 'active_support/rescuable'
4
+ require 'action_dispatch/http/upload'
5
+ require 'stringio'
6
+
7
+ module ActionController
8
+ # Raised when a required parameter is missing.
9
+ #
10
+ # params = ActionController::Parameters.new(a: {})
11
+ # params.fetch(:b)
12
+ # # => ActionController::ParameterMissing: param not found: b
13
+ # params.require(:a)
14
+ # # => ActionController::ParameterMissing: param not found: a
15
+ class ParameterMissing < KeyError
16
+ attr_reader :param # :nodoc:
17
+
18
+ def initialize(param) # :nodoc:
19
+ @param = param
20
+ super("param not found: #{param}")
21
+ end
22
+ end
23
+
24
+ # Raised when a supplied parameter is not expected.
25
+ #
26
+ # params = ActionController::Parameters.new(a: "123", b: "456")
27
+ # params.permit(:c)
28
+ # # => ActionController::UnpermittedParameters: found unexpected keys: a, b
29
+ class UnpermittedParameters < IndexError
30
+ attr_reader :params # :nodoc:
31
+
32
+ def initialize(params) # :nodoc:
33
+ @params = params
34
+ super("found unpermitted parameters: #{params.join(", ")}")
35
+ end
36
+ end
37
+
38
+ # == Action Controller \Parameters
39
+ #
40
+ # Allows to choose which attributes should be whitelisted for mass updating
41
+ # and thus prevent accidentally exposing that which shouldn’t be exposed.
42
+ # Provides two methods for this purpose: #require and #permit. The former is
43
+ # used to mark parameters as required. The latter is used to set the parameter
44
+ # as permitted and limit which attributes should be allowed for mass updating.
45
+ #
46
+ # params = ActionController::Parameters.new({
47
+ # person: {
48
+ # name: 'Francesco',
49
+ # age: 22,
50
+ # role: 'admin'
51
+ # }
52
+ # })
53
+ #
54
+ # permitted = params.require(:person).permit(:name, :age)
55
+ # permitted # => {"name"=>"Francesco", "age"=>22}
56
+ # permitted.class # => ActionController::Parameters
57
+ # permitted.permitted? # => true
58
+ #
59
+ # Person.first.update!(permitted)
60
+ # # => #<Person id: 1, name: "Francesco", age: 22, role: "user">
61
+ #
62
+ # It provides two options that controls the top-level behavior of new instances:
63
+ #
64
+ # * +permit_all_parameters+ - If it's +true+, all the parameters will be
65
+ # permitted by default. The default is +false+.
66
+ # * +action_on_unpermitted_parameters+ - Allow to control the behavior when parameters
67
+ # that are not explicitly permitted are found. The values can be <tt>:log</tt> to
68
+ # write a message on the logger or <tt>:raise</tt> to raise
69
+ # ActionController::UnpermittedParameters exception. The default value is <tt>:log</tt>
70
+ # in test and development environments, +false+ otherwise.
71
+ #
72
+ # Examples:
73
+ #
74
+ # params = ActionController::Parameters.new
75
+ # params.permitted? # => false
76
+ #
77
+ # ActionController::Parameters.permit_all_parameters = true
78
+ #
79
+ # params = ActionController::Parameters.new
80
+ # params.permitted? # => true
81
+ #
82
+ # params = ActionController::Parameters.new(a: "123", b: "456")
83
+ # params.permit(:c)
84
+ # # => {}
85
+ #
86
+ # ActionController::Parameters.action_on_unpermitted_parameters = :raise
87
+ #
88
+ # params = ActionController::Parameters.new(a: "123", b: "456")
89
+ # params.permit(:c)
90
+ # # => ActionController::UnpermittedParameters: found unpermitted keys: a, b
91
+ #
92
+ # <tt>ActionController::Parameters</tt> is inherited from
93
+ # <tt>ActiveSupport::HashWithIndifferentAccess</tt>, this means
94
+ # that you can fetch values using either <tt>:key</tt> or <tt>"key"</tt>.
95
+ #
96
+ # params = ActionController::Parameters.new(key: 'value')
97
+ # params[:key] # => "value"
98
+ # params["key"] # => "value"
99
+ class Parameters < ActiveSupport::HashWithIndifferentAccess
100
+ cattr_accessor :permit_all_parameters, instance_accessor: false
101
+ cattr_accessor :action_on_unpermitted_parameters, instance_accessor: false
102
+
103
+ # Never raise an UnpermittedParameters exception because of these params
104
+ # are present. They are added by Rails and it's of no concern.
105
+ NEVER_UNPERMITTED_PARAMS = %w( controller action )
106
+
107
+ # Returns a new instance of <tt>ActionController::Parameters</tt>.
108
+ # Also, sets the +permitted+ attribute to the default value of
109
+ # <tt>ActionController::Parameters.permit_all_parameters</tt>.
110
+ #
111
+ # class Person < ActiveRecord::Base
112
+ # end
113
+ #
114
+ # params = ActionController::Parameters.new(name: 'Francesco')
115
+ # params.permitted? # => false
116
+ # Person.new(params) # => ActiveModel::ForbiddenAttributesError
117
+ #
118
+ # ActionController::Parameters.permit_all_parameters = true
119
+ #
120
+ # params = ActionController::Parameters.new(name: 'Francesco')
121
+ # params.permitted? # => true
122
+ # Person.new(params) # => #<Person id: nil, name: "Francesco">
123
+ def initialize(attributes = nil)
124
+ super(attributes)
125
+ @permitted = self.class.permit_all_parameters
126
+ end
127
+
128
+ # Returns +true+ if the parameter is permitted, +false+ otherwise.
129
+ #
130
+ # params = ActionController::Parameters.new
131
+ # params.permitted? # => false
132
+ # params.permit!
133
+ # params.permitted? # => true
134
+ def permitted?
135
+ @permitted
136
+ end
137
+
138
+ # Sets the +permitted+ attribute to +true+. This can be used to pass
139
+ # mass assignment. Returns +self+.
140
+ #
141
+ # class Person < ActiveRecord::Base
142
+ # end
143
+ #
144
+ # params = ActionController::Parameters.new(name: 'Francesco')
145
+ # params.permitted? # => false
146
+ # Person.new(params) # => ActiveModel::ForbiddenAttributesError
147
+ # params.permit!
148
+ # params.permitted? # => true
149
+ # Person.new(params) # => #<Person id: nil, name: "Francesco">
150
+ def permit!
151
+ each_pair do |key, value|
152
+ convert_hashes_to_parameters(key, value)
153
+ self[key].permit! if self[key].respond_to? :permit!
154
+ end
155
+
156
+ @permitted = true
157
+ self
158
+ end
159
+
160
+ # Ensures that a parameter is present. If it's present, returns
161
+ # the parameter at the given +key+, otherwise raises an
162
+ # <tt>ActionController::ParameterMissing</tt> error.
163
+ #
164
+ # ActionController::Parameters.new(person: { name: 'Francesco' }).require(:person)
165
+ # # => {"name"=>"Francesco"}
166
+ #
167
+ # ActionController::Parameters.new(person: nil).require(:person)
168
+ # # => ActionController::ParameterMissing: param not found: person
169
+ #
170
+ # ActionController::Parameters.new(person: {}).require(:person)
171
+ # # => ActionController::ParameterMissing: param not found: person
172
+ def require(key)
173
+ self[key].presence || raise(ParameterMissing.new(key))
174
+ end
175
+
176
+ # Alias of #require.
177
+ alias :required :require
178
+
179
+ # Returns a new <tt>ActionController::Parameters</tt> instance that
180
+ # includes only the given +filters+ and sets the +permitted+ attribute
181
+ # for the object to +true+. This is useful for limiting which attributes
182
+ # should be allowed for mass updating.
183
+ #
184
+ # params = ActionController::Parameters.new(user: { name: 'Francesco', age: 22, role: 'admin' })
185
+ # permitted = params.require(:user).permit(:name, :age)
186
+ # permitted.permitted? # => true
187
+ # permitted.has_key?(:name) # => true
188
+ # permitted.has_key?(:age) # => true
189
+ # permitted.has_key?(:role) # => false
190
+ #
191
+ # Only permitted scalars pass the filter. For example, given
192
+ #
193
+ # params.permit(:name)
194
+ #
195
+ # +:name+ passes it is a key of +params+ whose associated value is of type
196
+ # +String+, +Symbol+, +NilClass+, +Numeric+, +TrueClass+, +FalseClass+,
197
+ # +Date+, +Time+, +DateTime+, +StringIO+, +IO+,
198
+ # +ActionDispatch::Http::UploadedFile+ or +Rack::Test::UploadedFile+.
199
+ # Otherwise, the key +:name+ is filtered out.
200
+ #
201
+ # You may declare that the parameter should be an array of permitted scalars
202
+ # by mapping it to an empty array:
203
+ #
204
+ # params.permit(tags: [])
205
+ #
206
+ # You can also use +permit+ on nested parameters, like:
207
+ #
208
+ # params = ActionController::Parameters.new({
209
+ # person: {
210
+ # name: 'Francesco',
211
+ # age: 22,
212
+ # pets: [{
213
+ # name: 'Purplish',
214
+ # category: 'dogs'
215
+ # }]
216
+ # }
217
+ # })
218
+ #
219
+ # permitted = params.permit(person: [ :name, { pets: :name } ])
220
+ # permitted.permitted? # => true
221
+ # permitted[:person][:name] # => "Francesco"
222
+ # permitted[:person][:age] # => nil
223
+ # permitted[:person][:pets][0][:name] # => "Purplish"
224
+ # permitted[:person][:pets][0][:category] # => nil
225
+ #
226
+ # Note that if you use +permit+ in a key that points to a hash,
227
+ # it won't allow all the hash. You also need to specify which
228
+ # attributes inside the hash should be whitelisted.
229
+ #
230
+ # params = ActionController::Parameters.new({
231
+ # person: {
232
+ # contact: {
233
+ # email: 'none@test.com',
234
+ # phone: '555-1234'
235
+ # }
236
+ # }
237
+ # })
238
+ #
239
+ # params.require(:person).permit(:contact)
240
+ # # => {}
241
+ #
242
+ # params.require(:person).permit(contact: :phone)
243
+ # # => {"contact"=>{"phone"=>"555-1234"}}
244
+ #
245
+ # params.require(:person).permit(contact: [ :email, :phone ])
246
+ # # => {"contact"=>{"email"=>"none@test.com", "phone"=>"555-1234"}}
247
+ def permit(*filters)
248
+ params = self.class.new
249
+
250
+ filters.flatten.each do |filter|
251
+ case filter
252
+ when Symbol, String
253
+ permitted_scalar_filter(params, filter)
254
+ when Hash then
255
+ hash_filter(params, filter)
256
+ end
257
+ end
258
+
259
+ unpermitted_parameters!(params) if self.class.action_on_unpermitted_parameters
260
+
261
+ params.permit!
262
+ end
263
+
264
+ # Returns a parameter for the given +key+. If not found,
265
+ # returns +nil+.
266
+ #
267
+ # params = ActionController::Parameters.new(person: { name: 'Francesco' })
268
+ # params[:person] # => {"name"=>"Francesco"}
269
+ # params[:none] # => nil
270
+ def [](key)
271
+ convert_hashes_to_parameters(key, super)
272
+ end
273
+
274
+ # Returns a parameter for the given +key+. If the +key+
275
+ # can't be found, there are several options: With no other arguments,
276
+ # it will raise an <tt>ActionController::ParameterMissing</tt> error;
277
+ # if more arguments are given, then that will be returned; if a block
278
+ # is given, then that will be run and its result returned.
279
+ #
280
+ # params = ActionController::Parameters.new(person: { name: 'Francesco' })
281
+ # params.fetch(:person) # => {"name"=>"Francesco"}
282
+ # params.fetch(:none) # => ActionController::ParameterMissing: param not found: none
283
+ # params.fetch(:none, 'Francesco') # => "Francesco"
284
+ # params.fetch(:none) { 'Francesco' } # => "Francesco"
285
+ def fetch(key, *args)
286
+ convert_hashes_to_parameters(key, super)
287
+ rescue KeyError
288
+ raise ActionController::ParameterMissing.new(key)
289
+ end
290
+
291
+ # Returns a new <tt>ActionController::Parameters</tt> instance that
292
+ # includes only the given +keys+. If the given +keys+
293
+ # don't exist, returns an empty hash.
294
+ #
295
+ # params = ActionController::Parameters.new(a: 1, b: 2, c: 3)
296
+ # params.slice(:a, :b) # => {"a"=>1, "b"=>2}
297
+ # params.slice(:d) # => {}
298
+ def slice(*keys)
299
+ self.class.new(super).tap do |new_instance|
300
+ new_instance.instance_variable_set :@permitted, @permitted
301
+ end
302
+ end
303
+
304
+ # Returns an exact copy of the <tt>ActionController::Parameters</tt>
305
+ # instance. +permitted+ state is kept on the duped object.
306
+ #
307
+ # params = ActionController::Parameters.new(a: 1)
308
+ # params.permit!
309
+ # params.permitted? # => true
310
+ # copy_params = params.dup # => {"a"=>1}
311
+ # copy_params.permitted? # => true
312
+ def dup
313
+ super.tap do |duplicate|
314
+ duplicate.instance_variable_set :@permitted, @permitted
315
+ end
316
+ end
317
+
318
+ private
319
+ def convert_hashes_to_parameters(key, value)
320
+ if value.is_a?(Parameters) || !value.is_a?(Hash)
321
+ value
322
+ else
323
+ # Convert to Parameters on first access
324
+ self[key] = self.class.new(value)
325
+ end
326
+ end
327
+
328
+ def each_element(object)
329
+ if object.is_a?(Array)
330
+ object.map { |el| yield el }.compact
331
+ elsif object.is_a?(Hash) && object.keys.all? { |k| k =~ /\A-?\d+\z/ }
332
+ hash = object.class.new
333
+ object.each { |k,v| hash[k] = yield v }
334
+ hash
335
+ else
336
+ yield object
337
+ end
338
+ end
339
+
340
+ def unpermitted_parameters!(params)
341
+ unpermitted_keys = unpermitted_keys(params)
342
+ if unpermitted_keys.any?
343
+ case self.class.action_on_unpermitted_parameters
344
+ when :log
345
+ name = "unpermitted_parameters.action_controller"
346
+ ActiveSupport::Notifications.instrument(name, keys: unpermitted_keys)
347
+ when :raise
348
+ raise ActionController::UnpermittedParameters.new(unpermitted_keys)
349
+ end
350
+ end
351
+ end
352
+
353
+ def unpermitted_keys(params)
354
+ self.keys - params.keys - NEVER_UNPERMITTED_PARAMS
355
+ end
356
+
357
+ #
358
+ # --- Filtering ----------------------------------------------------------
359
+ #
360
+
361
+ # This is a white list of permitted scalar types that includes the ones
362
+ # supported in XML and JSON requests.
363
+ #
364
+ # This list is in particular used to filter ordinary requests, String goes
365
+ # as first element to quickly short-circuit the common case.
366
+ #
367
+ # If you modify this collection please update the API of +permit+ above.
368
+ PERMITTED_SCALAR_TYPES = [
369
+ String,
370
+ Symbol,
371
+ NilClass,
372
+ Numeric,
373
+ TrueClass,
374
+ FalseClass,
375
+ Date,
376
+ Time,
377
+ # DateTimes are Dates, we document the type but avoid the redundant check.
378
+ StringIO,
379
+ IO,
380
+ ActionDispatch::Http::UploadedFile,
381
+ Rack::Test::UploadedFile,
382
+ ]
383
+
384
+ def permitted_scalar?(value)
385
+ PERMITTED_SCALAR_TYPES.any? {|type| value.is_a?(type)}
386
+ end
387
+
388
+ def permitted_scalar_filter(params, key)
389
+ if has_key?(key) && permitted_scalar?(self[key])
390
+ params[key] = self[key]
391
+ end
392
+
393
+ keys.grep(/\A#{Regexp.escape(key)}\(\d+[if]?\)\z/) do |k|
394
+ if permitted_scalar?(self[k])
395
+ params[k] = self[k]
396
+ end
397
+ end
398
+ end
399
+
400
+ def array_of_permitted_scalars?(value)
401
+ if value.is_a?(Array)
402
+ value.all? {|element| permitted_scalar?(element)}
403
+ end
404
+ end
405
+
406
+ def array_of_permitted_scalars_filter(params, key)
407
+ if has_key?(key) && array_of_permitted_scalars?(self[key])
408
+ params[key] = self[key]
409
+ end
410
+ end
411
+
412
+ EMPTY_ARRAY = []
413
+ def hash_filter(params, filter)
414
+ filter = filter.with_indifferent_access
415
+
416
+ # Slicing filters out non-declared keys.
417
+ slice(*filter.keys).each do |key, value|
418
+ return unless value
419
+
420
+ if filter[key] == EMPTY_ARRAY
421
+ # Declaration { comment_ids: [] }.
422
+ array_of_permitted_scalars_filter(params, key)
423
+ else
424
+ # Declaration { user: :name } or { user: [:name, :age, { address: ... }] }.
425
+ params[key] = each_element(value) do |element|
426
+ if element.is_a?(Hash)
427
+ element = self.class.new(element) unless element.respond_to?(:permit)
428
+ element.permit(*Array.wrap(filter[key]))
429
+ end
430
+ end
431
+ end
432
+ end
433
+ end
434
+ end
435
+
436
+ # == Strong \Parameters
437
+ #
438
+ # It provides an interface for protecting attributes from end-user
439
+ # assignment. This makes Action Controller parameters forbidden
440
+ # to be used in Active Model mass assignment until they have been
441
+ # whitelisted.
442
+ #
443
+ # In addition, parameters can be marked as required and flow through a
444
+ # predefined raise/rescue flow to end up as a 400 Bad Request with no
445
+ # effort.
446
+ #
447
+ # class PeopleController < ActionController::Base
448
+ # # Using "Person.create(params[:person])" would raise an
449
+ # # ActiveModel::ForbiddenAttributes exception because it'd
450
+ # # be using mass assignment without an explicit permit step.
451
+ # # This is the recommended form:
452
+ # def create
453
+ # Person.create(person_params)
454
+ # end
455
+ #
456
+ # # This will pass with flying colors as long as there's a person key in the
457
+ # # parameters, otherwise it'll raise an ActionController::MissingParameter
458
+ # # exception, which will get caught by ActionController::Base and turned
459
+ # # into a 400 Bad Request reply.
460
+ # def update
461
+ # redirect_to current_account.people.find(params[:id]).tap { |person|
462
+ # person.update!(person_params)
463
+ # }
464
+ # end
465
+ #
466
+ # private
467
+ # # Using a private method to encapsulate the permissible parameters is
468
+ # # just a good pattern since you'll be able to reuse the same permit
469
+ # # list between create and update. Also, you can specialize this method
470
+ # # with per-user checking of permissible attributes.
471
+ # def person_params
472
+ # params.require(:person).permit(:name, :age)
473
+ # end
474
+ # end
475
+ #
476
+ # In order to use <tt>accepts_nested_attribute_for</tt> with Strong \Parameters, you
477
+ # will need to specify which nested attributes should be whitelisted.
478
+ #
479
+ # class Person
480
+ # has_many :pets
481
+ # accepts_nested_attributes_for :pets
482
+ # end
483
+ #
484
+ # class PeopleController < ActionController::Base
485
+ # def create
486
+ # Person.create(person_params)
487
+ # end
488
+ #
489
+ # ...
490
+ #
491
+ # private
492
+ #
493
+ # def person_params
494
+ # # It's mandatory to specify the nested attributes that should be whitelisted.
495
+ # # If you use `permit` with just the key that points to the nested attributes hash,
496
+ # # it will return an empty hash.
497
+ # params.require(:person).permit(:name, :age, pets_attributes: [ :name, :category ])
498
+ # end
499
+ # end
500
+ #
501
+ # See ActionController::Parameters.require and ActionController::Parameters.permit
502
+ # for more information.
503
+ module StrongParameters
504
+ extend ActiveSupport::Concern
505
+ include ActiveSupport::Rescuable
506
+
507
+ # Returns a new ActionController::Parameters object that
508
+ # has been instantiated with the <tt>request.parameters</tt>.
509
+ def params
510
+ @_params ||= Parameters.new(request.parameters)
511
+ end
512
+
513
+ # Assigns the given +value+ to the +params+ hash. If +value+
514
+ # is a Hash, this will create an ActionController::Parameters
515
+ # object that has been instantiated with the given +value+ hash.
516
+ def params=(value)
517
+ @_params = value.is_a?(Hash) ? Parameters.new(value) : value
518
+ end
519
+ end
520
+ end
@@ -4,30 +4,25 @@ module ActionController
4
4
 
5
5
  include RackDelegation
6
6
 
7
- def recycle!
8
- @_url_options = nil
9
- end
10
-
11
-
12
- # TODO: Clean this up
13
- def process_with_new_base_test(request, response)
14
- @_request = request
15
- @_response = response
16
- @_response.request = request
17
- ret = process(request.parameters[:action])
18
- if cookies = @_request.env['action_dispatch.cookies']
19
- cookies.write(@_response)
20
- end
21
- @_response.prepare!
22
- ret
23
- end
24
-
25
7
  # TODO : Rewrite tests using controller.headers= to use Rack env
26
8
  def headers=(new_headers)
27
9
  @_response ||= ActionDispatch::Response.new
28
10
  @_response.headers.replace(new_headers)
29
11
  end
30
12
 
13
+ # Behavior specific to functional tests
14
+ module Functional # :nodoc:
15
+ def set_response!(request)
16
+ end
17
+
18
+ def recycle!
19
+ @_url_options = nil
20
+ self.response_body = nil
21
+ self.formats = nil
22
+ self.params = nil
23
+ end
24
+ end
25
+
31
26
  module ClassMethods
32
27
  def before_filters
33
28
  _process_action_callbacks.find_all{|x| x.kind == :before}.map{|x| x.name}
@@ -1,25 +1,22 @@
1
- # Includes +url_for+ into the host class. The class has to provide a +RouteSet+ by implementing
2
- # the <tt>_routes</tt> method. Otherwise, an exception will be raised.
3
- #
4
- # In addition to <tt>AbstractController::UrlFor</tt>, this module accesses the HTTP layer to define
5
- # url options like the +host+. In order to do so, this module requires the host class
6
- # to implement +env+ and +request+, which need to be a Rack-compatible.
7
- #
8
- # Example:
9
- #
10
- # class RootUrl
11
- # include ActionController::UrlFor
12
- # include Rails.application.routes.url_helpers
13
- #
14
- # delegate :env, :request, :to => :controller
15
- #
16
- # def initialize(controller)
17
- # @controller = controller
18
- # @url = root_path # named route from the application.
19
- # end
20
- # end
21
- #
22
1
  module ActionController
2
+ # Includes +url_for+ into the host class. The class has to provide a +RouteSet+ by implementing
3
+ # the <tt>_routes</tt> method. Otherwise, an exception will be raised.
4
+ #
5
+ # In addition to <tt>AbstractController::UrlFor</tt>, this module accesses the HTTP layer to define
6
+ # url options like the +host+. In order to do so, this module requires the host class
7
+ # to implement +env+ and +request+, which need to be a Rack-compatible.
8
+ #
9
+ # class RootUrl
10
+ # include ActionController::UrlFor
11
+ # include Rails.application.routes.url_helpers
12
+ #
13
+ # delegate :env, :request, to: :controller
14
+ #
15
+ # def initialize(controller)
16
+ # @controller = controller
17
+ # @url = root_path # named route from the application.
18
+ # end
19
+ # end
23
20
  module UrlFor
24
21
  extend ActiveSupport::Concern
25
22
 
@@ -30,18 +27,24 @@ module ActionController
30
27
  :host => request.host,
31
28
  :port => request.optional_port,
32
29
  :protocol => request.protocol,
33
- :_path_segments => request.symbolized_path_parameters
30
+ :_recall => request.symbolized_path_parameters
34
31
  ).freeze
35
32
 
36
- if _routes.equal?(env["action_dispatch.routes"])
33
+ if (same_origin = _routes.equal?(env["action_dispatch.routes"])) ||
34
+ (script_name = env["ROUTES_#{_routes.object_id}_SCRIPT_NAME"]) ||
35
+ (original_script_name = env['ORIGINAL_SCRIPT_NAME'])
36
+
37
37
  @_url_options.dup.tap do |options|
38
- options[:script_name] = request.script_name.dup
38
+ if original_script_name
39
+ options[:original_script_name] = original_script_name
40
+ else
41
+ options[:script_name] = same_origin ? request.script_name.dup : script_name
42
+ end
39
43
  options.freeze
40
44
  end
41
45
  else
42
46
  @_url_options
43
47
  end
44
48
  end
45
-
46
49
  end
47
50
  end