actionpack 6.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (181) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +311 -0
  3. data/MIT-LICENSE +21 -0
  4. data/README.rdoc +58 -0
  5. data/lib/abstract_controller.rb +27 -0
  6. data/lib/abstract_controller/asset_paths.rb +12 -0
  7. data/lib/abstract_controller/base.rb +267 -0
  8. data/lib/abstract_controller/caching.rb +66 -0
  9. data/lib/abstract_controller/caching/fragments.rb +150 -0
  10. data/lib/abstract_controller/callbacks.rb +224 -0
  11. data/lib/abstract_controller/collector.rb +43 -0
  12. data/lib/abstract_controller/error.rb +6 -0
  13. data/lib/abstract_controller/helpers.rb +194 -0
  14. data/lib/abstract_controller/logger.rb +14 -0
  15. data/lib/abstract_controller/railties/routes_helpers.rb +20 -0
  16. data/lib/abstract_controller/rendering.rb +127 -0
  17. data/lib/abstract_controller/translation.rb +32 -0
  18. data/lib/abstract_controller/url_for.rb +35 -0
  19. data/lib/action_controller.rb +67 -0
  20. data/lib/action_controller/api.rb +150 -0
  21. data/lib/action_controller/api/api_rendering.rb +16 -0
  22. data/lib/action_controller/base.rb +271 -0
  23. data/lib/action_controller/caching.rb +46 -0
  24. data/lib/action_controller/form_builder.rb +50 -0
  25. data/lib/action_controller/log_subscriber.rb +81 -0
  26. data/lib/action_controller/metal.rb +256 -0
  27. data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
  28. data/lib/action_controller/metal/conditional_get.rb +280 -0
  29. data/lib/action_controller/metal/content_security_policy.rb +52 -0
  30. data/lib/action_controller/metal/cookies.rb +16 -0
  31. data/lib/action_controller/metal/data_streaming.rb +151 -0
  32. data/lib/action_controller/metal/default_headers.rb +17 -0
  33. data/lib/action_controller/metal/etag_with_flash.rb +18 -0
  34. data/lib/action_controller/metal/etag_with_template_digest.rb +57 -0
  35. data/lib/action_controller/metal/exceptions.rb +74 -0
  36. data/lib/action_controller/metal/flash.rb +61 -0
  37. data/lib/action_controller/metal/force_ssl.rb +58 -0
  38. data/lib/action_controller/metal/head.rb +60 -0
  39. data/lib/action_controller/metal/helpers.rb +122 -0
  40. data/lib/action_controller/metal/http_authentication.rb +518 -0
  41. data/lib/action_controller/metal/implicit_render.rb +63 -0
  42. data/lib/action_controller/metal/instrumentation.rb +105 -0
  43. data/lib/action_controller/metal/live.rb +314 -0
  44. data/lib/action_controller/metal/mime_responds.rb +324 -0
  45. data/lib/action_controller/metal/parameter_encoding.rb +51 -0
  46. data/lib/action_controller/metal/params_wrapper.rb +297 -0
  47. data/lib/action_controller/metal/redirecting.rb +133 -0
  48. data/lib/action_controller/metal/renderers.rb +181 -0
  49. data/lib/action_controller/metal/rendering.rb +122 -0
  50. data/lib/action_controller/metal/request_forgery_protection.rb +456 -0
  51. data/lib/action_controller/metal/rescue.rb +28 -0
  52. data/lib/action_controller/metal/streaming.rb +223 -0
  53. data/lib/action_controller/metal/strong_parameters.rb +1105 -0
  54. data/lib/action_controller/metal/testing.rb +16 -0
  55. data/lib/action_controller/metal/url_for.rb +58 -0
  56. data/lib/action_controller/railtie.rb +89 -0
  57. data/lib/action_controller/railties/helpers.rb +24 -0
  58. data/lib/action_controller/renderer.rb +130 -0
  59. data/lib/action_controller/template_assertions.rb +11 -0
  60. data/lib/action_controller/test_case.rb +626 -0
  61. data/lib/action_dispatch.rb +114 -0
  62. data/lib/action_dispatch/http/cache.rb +226 -0
  63. data/lib/action_dispatch/http/content_disposition.rb +45 -0
  64. data/lib/action_dispatch/http/content_security_policy.rb +284 -0
  65. data/lib/action_dispatch/http/filter_parameters.rb +86 -0
  66. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  67. data/lib/action_dispatch/http/headers.rb +132 -0
  68. data/lib/action_dispatch/http/mime_negotiation.rb +177 -0
  69. data/lib/action_dispatch/http/mime_type.rb +350 -0
  70. data/lib/action_dispatch/http/mime_types.rb +50 -0
  71. data/lib/action_dispatch/http/parameter_filter.rb +12 -0
  72. data/lib/action_dispatch/http/parameters.rb +136 -0
  73. data/lib/action_dispatch/http/rack_cache.rb +63 -0
  74. data/lib/action_dispatch/http/request.rb +427 -0
  75. data/lib/action_dispatch/http/response.rb +534 -0
  76. data/lib/action_dispatch/http/upload.rb +92 -0
  77. data/lib/action_dispatch/http/url.rb +350 -0
  78. data/lib/action_dispatch/journey.rb +7 -0
  79. data/lib/action_dispatch/journey/formatter.rb +189 -0
  80. data/lib/action_dispatch/journey/gtg/builder.rb +164 -0
  81. data/lib/action_dispatch/journey/gtg/simulator.rb +41 -0
  82. data/lib/action_dispatch/journey/gtg/transition_table.rb +158 -0
  83. data/lib/action_dispatch/journey/nfa/builder.rb +78 -0
  84. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  85. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  86. data/lib/action_dispatch/journey/nfa/transition_table.rb +120 -0
  87. data/lib/action_dispatch/journey/nodes/node.rb +141 -0
  88. data/lib/action_dispatch/journey/parser.rb +199 -0
  89. data/lib/action_dispatch/journey/parser.y +50 -0
  90. data/lib/action_dispatch/journey/parser_extras.rb +31 -0
  91. data/lib/action_dispatch/journey/path/pattern.rb +203 -0
  92. data/lib/action_dispatch/journey/route.rb +204 -0
  93. data/lib/action_dispatch/journey/router.rb +153 -0
  94. data/lib/action_dispatch/journey/router/utils.rb +102 -0
  95. data/lib/action_dispatch/journey/routes.rb +81 -0
  96. data/lib/action_dispatch/journey/scanner.rb +71 -0
  97. data/lib/action_dispatch/journey/visitors.rb +268 -0
  98. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  99. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  100. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  101. data/lib/action_dispatch/middleware/actionable_exceptions.rb +39 -0
  102. data/lib/action_dispatch/middleware/callbacks.rb +34 -0
  103. data/lib/action_dispatch/middleware/cookies.rb +663 -0
  104. data/lib/action_dispatch/middleware/debug_exceptions.rb +185 -0
  105. data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
  106. data/lib/action_dispatch/middleware/debug_view.rb +68 -0
  107. data/lib/action_dispatch/middleware/exception_wrapper.rb +181 -0
  108. data/lib/action_dispatch/middleware/executor.rb +21 -0
  109. data/lib/action_dispatch/middleware/flash.rb +300 -0
  110. data/lib/action_dispatch/middleware/host_authorization.rb +103 -0
  111. data/lib/action_dispatch/middleware/public_exceptions.rb +61 -0
  112. data/lib/action_dispatch/middleware/reloader.rb +12 -0
  113. data/lib/action_dispatch/middleware/remote_ip.rb +181 -0
  114. data/lib/action_dispatch/middleware/request_id.rb +43 -0
  115. data/lib/action_dispatch/middleware/session/abstract_store.rb +92 -0
  116. data/lib/action_dispatch/middleware/session/cache_store.rb +54 -0
  117. data/lib/action_dispatch/middleware/session/cookie_store.rb +113 -0
  118. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +28 -0
  119. data/lib/action_dispatch/middleware/show_exceptions.rb +62 -0
  120. data/lib/action_dispatch/middleware/ssl.rb +150 -0
  121. data/lib/action_dispatch/middleware/stack.rb +148 -0
  122. data/lib/action_dispatch/middleware/static.rb +129 -0
  123. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  124. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  125. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +24 -0
  126. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  127. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +29 -0
  128. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +62 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
  132. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
  133. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +38 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
  136. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +15 -0
  137. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +165 -0
  138. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
  139. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  140. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  141. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  142. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  143. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  144. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  145. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  146. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  147. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  148. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  149. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +203 -0
  150. data/lib/action_dispatch/railtie.rb +58 -0
  151. data/lib/action_dispatch/request/session.rb +242 -0
  152. data/lib/action_dispatch/request/utils.rb +78 -0
  153. data/lib/action_dispatch/routing.rb +261 -0
  154. data/lib/action_dispatch/routing/endpoint.rb +17 -0
  155. data/lib/action_dispatch/routing/inspector.rb +274 -0
  156. data/lib/action_dispatch/routing/mapper.rb +2289 -0
  157. data/lib/action_dispatch/routing/polymorphic_routes.rb +351 -0
  158. data/lib/action_dispatch/routing/redirection.rb +201 -0
  159. data/lib/action_dispatch/routing/route_set.rb +887 -0
  160. data/lib/action_dispatch/routing/routes_proxy.rb +69 -0
  161. data/lib/action_dispatch/routing/url_for.rb +237 -0
  162. data/lib/action_dispatch/system_test_case.rb +168 -0
  163. data/lib/action_dispatch/system_testing/browser.rb +80 -0
  164. data/lib/action_dispatch/system_testing/driver.rb +68 -0
  165. data/lib/action_dispatch/system_testing/server.rb +31 -0
  166. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +97 -0
  167. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +33 -0
  168. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
  169. data/lib/action_dispatch/testing/assertion_response.rb +47 -0
  170. data/lib/action_dispatch/testing/assertions.rb +24 -0
  171. data/lib/action_dispatch/testing/assertions/response.rb +106 -0
  172. data/lib/action_dispatch/testing/assertions/routing.rb +234 -0
  173. data/lib/action_dispatch/testing/integration.rb +659 -0
  174. data/lib/action_dispatch/testing/request_encoder.rb +55 -0
  175. data/lib/action_dispatch/testing/test_process.rb +50 -0
  176. data/lib/action_dispatch/testing/test_request.rb +71 -0
  177. data/lib/action_dispatch/testing/test_response.rb +25 -0
  178. data/lib/action_pack.rb +26 -0
  179. data/lib/action_pack/gem_version.rb +17 -0
  180. data/lib/action_pack/version.rb +10 -0
  181. metadata +329 -0
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/hash/indifferent_access"
4
+
5
+ module ActionDispatch
6
+ class Request
7
+ class Utils # :nodoc:
8
+ mattr_accessor :perform_deep_munge, default: true
9
+
10
+ def self.each_param_value(params, &block)
11
+ case params
12
+ when Array
13
+ params.each { |element| each_param_value(element, &block) }
14
+ when Hash
15
+ params.each_value { |value| each_param_value(value, &block) }
16
+ when String
17
+ block.call params
18
+ end
19
+ end
20
+
21
+ def self.normalize_encode_params(params)
22
+ if perform_deep_munge
23
+ NoNilParamEncoder.normalize_encode_params params
24
+ else
25
+ ParamEncoder.normalize_encode_params params
26
+ end
27
+ end
28
+
29
+ def self.check_param_encoding(params)
30
+ case params
31
+ when Array
32
+ params.each { |element| check_param_encoding(element) }
33
+ when Hash
34
+ params.each_value { |value| check_param_encoding(value) }
35
+ when String
36
+ unless params.valid_encoding?
37
+ # Raise Rack::Utils::InvalidParameterError for consistency with Rack.
38
+ # ActionDispatch::Request#GET will re-raise as a BadRequest error.
39
+ raise Rack::Utils::InvalidParameterError, "Invalid encoding for parameter: #{params.scrub}"
40
+ end
41
+ end
42
+ end
43
+
44
+ class ParamEncoder # :nodoc:
45
+ # Convert nested Hash to HashWithIndifferentAccess.
46
+ def self.normalize_encode_params(params)
47
+ case params
48
+ when Array
49
+ handle_array params
50
+ when Hash
51
+ if params.has_key?(:tempfile)
52
+ ActionDispatch::Http::UploadedFile.new(params)
53
+ else
54
+ params.each_with_object({}) do |(key, val), new_hash|
55
+ new_hash[key] = normalize_encode_params(val)
56
+ end.with_indifferent_access
57
+ end
58
+ else
59
+ params
60
+ end
61
+ end
62
+
63
+ def self.handle_array(params)
64
+ params.map! { |el| normalize_encode_params(el) }
65
+ end
66
+ end
67
+
68
+ # Remove nils from the params hash.
69
+ class NoNilParamEncoder < ParamEncoder # :nodoc:
70
+ def self.handle_array(params)
71
+ list = super
72
+ list.compact!
73
+ list
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,261 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/string/filters"
4
+
5
+ module ActionDispatch
6
+ # The routing module provides URL rewriting in native Ruby. It's a way to
7
+ # redirect incoming requests to controllers and actions. This replaces
8
+ # mod_rewrite rules. Best of all, Rails' \Routing works with any web server.
9
+ # Routes are defined in <tt>config/routes.rb</tt>.
10
+ #
11
+ # Think of creating routes as drawing a map for your requests. The map tells
12
+ # them where to go based on some predefined pattern:
13
+ #
14
+ # Rails.application.routes.draw do
15
+ # Pattern 1 tells some request to go to one place
16
+ # Pattern 2 tell them to go to another
17
+ # ...
18
+ # end
19
+ #
20
+ # The following symbols are special:
21
+ #
22
+ # :controller maps to your controller name
23
+ # :action maps to an action with your controllers
24
+ #
25
+ # Other names simply map to a parameter as in the case of <tt>:id</tt>.
26
+ #
27
+ # == Resources
28
+ #
29
+ # Resource routing allows you to quickly declare all of the common routes
30
+ # for a given resourceful controller. Instead of declaring separate routes
31
+ # for your +index+, +show+, +new+, +edit+, +create+, +update+ and +destroy+
32
+ # actions, a resourceful route declares them in a single line of code:
33
+ #
34
+ # resources :photos
35
+ #
36
+ # Sometimes, you have a resource that clients always look up without
37
+ # referencing an ID. A common example, /profile always shows the profile of
38
+ # the currently logged in user. In this case, you can use a singular resource
39
+ # to map /profile (rather than /profile/:id) to the show action.
40
+ #
41
+ # resource :profile
42
+ #
43
+ # It's common to have resources that are logically children of other
44
+ # resources:
45
+ #
46
+ # resources :magazines do
47
+ # resources :ads
48
+ # end
49
+ #
50
+ # You may wish to organize groups of controllers under a namespace. Most
51
+ # commonly, you might group a number of administrative controllers under
52
+ # an +admin+ namespace. You would place these controllers under the
53
+ # <tt>app/controllers/admin</tt> directory, and you can group them together
54
+ # in your router:
55
+ #
56
+ # namespace "admin" do
57
+ # resources :posts, :comments
58
+ # end
59
+ #
60
+ # Alternatively, you can add prefixes to your path without using a separate
61
+ # directory by using +scope+. +scope+ takes additional options which
62
+ # apply to all enclosed routes.
63
+ #
64
+ # scope path: "/cpanel", as: 'admin' do
65
+ # resources :posts, :comments
66
+ # end
67
+ #
68
+ # For more, see <tt>Routing::Mapper::Resources#resources</tt>,
69
+ # <tt>Routing::Mapper::Scoping#namespace</tt>, and
70
+ # <tt>Routing::Mapper::Scoping#scope</tt>.
71
+ #
72
+ # == Non-resourceful routes
73
+ #
74
+ # For routes that don't fit the <tt>resources</tt> mold, you can use the HTTP helper
75
+ # methods <tt>get</tt>, <tt>post</tt>, <tt>patch</tt>, <tt>put</tt> and <tt>delete</tt>.
76
+ #
77
+ # get 'post/:id', to: 'posts#show'
78
+ # post 'post/:id', to: 'posts#create_comment'
79
+ #
80
+ # Now, if you POST to <tt>/posts/:id</tt>, it will route to the <tt>create_comment</tt> action. A GET on the same
81
+ # URL will route to the <tt>show</tt> action.
82
+ #
83
+ # If your route needs to respond to more than one HTTP method (or all methods) then using the
84
+ # <tt>:via</tt> option on <tt>match</tt> is preferable.
85
+ #
86
+ # match 'post/:id', to: 'posts#show', via: [:get, :post]
87
+ #
88
+ # == Named routes
89
+ #
90
+ # Routes can be named by passing an <tt>:as</tt> option,
91
+ # allowing for easy reference within your source as +name_of_route_url+
92
+ # for the full URL and +name_of_route_path+ for the URI path.
93
+ #
94
+ # Example:
95
+ #
96
+ # # In config/routes.rb
97
+ # get '/login', to: 'accounts#login', as: 'login'
98
+ #
99
+ # # With render, redirect_to, tests, etc.
100
+ # redirect_to login_url
101
+ #
102
+ # Arguments can be passed as well.
103
+ #
104
+ # redirect_to show_item_path(id: 25)
105
+ #
106
+ # Use <tt>root</tt> as a shorthand to name a route for the root path "/".
107
+ #
108
+ # # In config/routes.rb
109
+ # root to: 'blogs#index'
110
+ #
111
+ # # would recognize http://www.example.com/ as
112
+ # params = { controller: 'blogs', action: 'index' }
113
+ #
114
+ # # and provide these named routes
115
+ # root_url # => 'http://www.example.com/'
116
+ # root_path # => '/'
117
+ #
118
+ # Note: when using +controller+, the route is simply named after the
119
+ # method you call on the block parameter rather than map.
120
+ #
121
+ # # In config/routes.rb
122
+ # controller :blog do
123
+ # get 'blog/show', to: :list
124
+ # get 'blog/delete', to: :delete
125
+ # get 'blog/edit', to: :edit
126
+ # end
127
+ #
128
+ # # provides named routes for show, delete, and edit
129
+ # link_to @article.title, blog_show_path(id: @article.id)
130
+ #
131
+ # == Pretty URLs
132
+ #
133
+ # Routes can generate pretty URLs. For example:
134
+ #
135
+ # get '/articles/:year/:month/:day', to: 'articles#find_by_id', constraints: {
136
+ # year: /\d{4}/,
137
+ # month: /\d{1,2}/,
138
+ # day: /\d{1,2}/
139
+ # }
140
+ #
141
+ # Using the route above, the URL "http://localhost:3000/articles/2005/11/06"
142
+ # maps to
143
+ #
144
+ # params = {year: '2005', month: '11', day: '06'}
145
+ #
146
+ # == Regular Expressions and parameters
147
+ # You can specify a regular expression to define a format for a parameter.
148
+ #
149
+ # controller 'geocode' do
150
+ # get 'geocode/:postalcode', to: :show, constraints: {
151
+ # postalcode: /\d{5}(-\d{4})?/
152
+ # }
153
+ # end
154
+ #
155
+ # Constraints can include the 'ignorecase' and 'extended syntax' regular
156
+ # expression modifiers:
157
+ #
158
+ # controller 'geocode' do
159
+ # get 'geocode/:postalcode', to: :show, constraints: {
160
+ # postalcode: /hx\d\d\s\d[a-z]{2}/i
161
+ # }
162
+ # end
163
+ #
164
+ # controller 'geocode' do
165
+ # get 'geocode/:postalcode', to: :show, constraints: {
166
+ # postalcode: /# Postalcode format
167
+ # \d{5} #Prefix
168
+ # (-\d{4})? #Suffix
169
+ # /x
170
+ # }
171
+ # end
172
+ #
173
+ # Using the multiline modifier will raise an +ArgumentError+.
174
+ # Encoding regular expression modifiers are silently ignored. The
175
+ # match will always use the default encoding or ASCII.
176
+ #
177
+ # == External redirects
178
+ #
179
+ # You can redirect any path to another path using the redirect helper in your router:
180
+ #
181
+ # get "/stories", to: redirect("/posts")
182
+ #
183
+ # == Unicode character routes
184
+ #
185
+ # You can specify unicode character routes in your router:
186
+ #
187
+ # get "こんにちは", to: "welcome#index"
188
+ #
189
+ # == Routing to Rack Applications
190
+ #
191
+ # Instead of a String, like <tt>posts#index</tt>, which corresponds to the
192
+ # index action in the PostsController, you can specify any Rack application
193
+ # as the endpoint for a matcher:
194
+ #
195
+ # get "/application.js", to: Sprockets
196
+ #
197
+ # == Reloading routes
198
+ #
199
+ # You can reload routes if you feel you must:
200
+ #
201
+ # Rails.application.reload_routes!
202
+ #
203
+ # This will clear all named routes and reload config/routes.rb if the file has been modified from
204
+ # last load. To absolutely force reloading, use <tt>reload!</tt>.
205
+ #
206
+ # == Testing Routes
207
+ #
208
+ # The two main methods for testing your routes:
209
+ #
210
+ # === +assert_routing+
211
+ #
212
+ # def test_movie_route_properly_splits
213
+ # opts = {controller: "plugin", action: "checkout", id: "2"}
214
+ # assert_routing "plugin/checkout/2", opts
215
+ # end
216
+ #
217
+ # +assert_routing+ lets you test whether or not the route properly resolves into options.
218
+ #
219
+ # === +assert_recognizes+
220
+ #
221
+ # def test_route_has_options
222
+ # opts = {controller: "plugin", action: "show", id: "12"}
223
+ # assert_recognizes opts, "/plugins/show/12"
224
+ # end
225
+ #
226
+ # Note the subtle difference between the two: +assert_routing+ tests that
227
+ # a URL fits options while +assert_recognizes+ tests that a URL
228
+ # breaks into parameters properly.
229
+ #
230
+ # In tests you can simply pass the URL or named route to +get+ or +post+.
231
+ #
232
+ # def send_to_jail
233
+ # get '/jail'
234
+ # assert_response :success
235
+ # end
236
+ #
237
+ # def goes_to_login
238
+ # get login_url
239
+ # #...
240
+ # end
241
+ #
242
+ # == View a list of all your routes
243
+ #
244
+ # rails routes
245
+ #
246
+ # Target a specific controller with <tt>-c</tt>, or grep routes
247
+ # using <tt>-g</tt>. Useful in conjunction with <tt>--expanded</tt>
248
+ # which displays routes vertically.
249
+ module Routing
250
+ extend ActiveSupport::Autoload
251
+
252
+ autoload :Mapper
253
+ autoload :RouteSet
254
+ autoload :RoutesProxy
255
+ autoload :UrlFor
256
+ autoload :PolymorphicRoutes
257
+
258
+ SEPARATORS = %w( / . ? ) #:nodoc:
259
+ HTTP_METHODS = [:get, :head, :post, :patch, :put, :delete, :options] #:nodoc:
260
+ end
261
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch
4
+ module Routing
5
+ class Endpoint # :nodoc:
6
+ def dispatcher?; false; end
7
+ def redirect?; false; end
8
+ def matches?(req); true; end
9
+ def app; self; end
10
+ def rack_app; app; end
11
+
12
+ def engine?
13
+ rack_app.is_a?(Class) && rack_app < Rails::Engine
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,274 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "delegate"
4
+ require "io/console/size"
5
+
6
+ module ActionDispatch
7
+ module Routing
8
+ class RouteWrapper < SimpleDelegator
9
+ def endpoint
10
+ app.dispatcher? ? "#{controller}##{action}" : rack_app.inspect
11
+ end
12
+
13
+ def constraints
14
+ requirements.except(:controller, :action)
15
+ end
16
+
17
+ def rack_app
18
+ app.rack_app
19
+ end
20
+
21
+ def path
22
+ super.spec.to_s
23
+ end
24
+
25
+ def name
26
+ super.to_s
27
+ end
28
+
29
+ def reqs
30
+ @reqs ||= begin
31
+ reqs = endpoint
32
+ reqs += " #{constraints}" unless constraints.empty?
33
+ reqs
34
+ end
35
+ end
36
+
37
+ def controller
38
+ parts.include?(:controller) ? ":controller" : requirements[:controller]
39
+ end
40
+
41
+ def action
42
+ parts.include?(:action) ? ":action" : requirements[:action]
43
+ end
44
+
45
+ def internal?
46
+ internal
47
+ end
48
+
49
+ def engine?
50
+ app.engine?
51
+ end
52
+ end
53
+
54
+ ##
55
+ # This class is just used for displaying route information when someone
56
+ # executes `rails routes` or looks at the RoutingError page.
57
+ # People should not use this class.
58
+ class RoutesInspector # :nodoc:
59
+ def initialize(routes)
60
+ @engines = {}
61
+ @routes = routes
62
+ end
63
+
64
+ def format(formatter, filter = {})
65
+ routes_to_display = filter_routes(normalize_filter(filter))
66
+ routes = collect_routes(routes_to_display)
67
+ if routes.none?
68
+ formatter.no_routes(collect_routes(@routes), filter)
69
+ return formatter.result
70
+ end
71
+
72
+ formatter.header routes
73
+ formatter.section routes
74
+
75
+ @engines.each do |name, engine_routes|
76
+ formatter.section_title "Routes for #{name}"
77
+ formatter.section engine_routes
78
+ end
79
+
80
+ formatter.result
81
+ end
82
+
83
+ private
84
+ def normalize_filter(filter)
85
+ if filter[:controller]
86
+ { controller: /#{filter[:controller].underscore.sub(/_?controller\z/, "")}/ }
87
+ elsif filter[:grep]
88
+ { controller: /#{filter[:grep]}/, action: /#{filter[:grep]}/,
89
+ verb: /#{filter[:grep]}/, name: /#{filter[:grep]}/, path: /#{filter[:grep]}/ }
90
+ end
91
+ end
92
+
93
+ def filter_routes(filter)
94
+ if filter
95
+ @routes.select do |route|
96
+ route_wrapper = RouteWrapper.new(route)
97
+ filter.any? { |default, value| route_wrapper.send(default) =~ value }
98
+ end
99
+ else
100
+ @routes
101
+ end
102
+ end
103
+
104
+ def collect_routes(routes)
105
+ routes.collect do |route|
106
+ RouteWrapper.new(route)
107
+ end.reject(&:internal?).collect do |route|
108
+ collect_engine_routes(route)
109
+
110
+ { name: route.name,
111
+ verb: route.verb,
112
+ path: route.path,
113
+ reqs: route.reqs }
114
+ end
115
+ end
116
+
117
+ def collect_engine_routes(route)
118
+ name = route.endpoint
119
+ return unless route.engine?
120
+ return if @engines[name]
121
+
122
+ routes = route.rack_app.routes
123
+ if routes.is_a?(ActionDispatch::Routing::RouteSet)
124
+ @engines[name] = collect_routes(routes.routes)
125
+ end
126
+ end
127
+ end
128
+
129
+ module ConsoleFormatter
130
+ class Base
131
+ def initialize
132
+ @buffer = []
133
+ end
134
+
135
+ def result
136
+ @buffer.join("\n")
137
+ end
138
+
139
+ def section_title(title)
140
+ end
141
+
142
+ def section(routes)
143
+ end
144
+
145
+ def header(routes)
146
+ end
147
+
148
+ def no_routes(routes, filter)
149
+ @buffer <<
150
+ if routes.none?
151
+ <<~MESSAGE
152
+ You don't have any routes defined!
153
+
154
+ Please add some routes in config/routes.rb.
155
+ MESSAGE
156
+ elsif filter.key?(:controller)
157
+ "No routes were found for this controller."
158
+ elsif filter.key?(:grep)
159
+ "No routes were found for this grep pattern."
160
+ end
161
+
162
+ @buffer << "For more information about routes, see the Rails guide: https://guides.rubyonrails.org/routing.html."
163
+ end
164
+ end
165
+
166
+ class Sheet < Base
167
+ def section_title(title)
168
+ @buffer << "\n#{title}:"
169
+ end
170
+
171
+ def section(routes)
172
+ @buffer << draw_section(routes)
173
+ end
174
+
175
+ def header(routes)
176
+ @buffer << draw_header(routes)
177
+ end
178
+
179
+ private
180
+
181
+ def draw_section(routes)
182
+ header_lengths = ["Prefix", "Verb", "URI Pattern"].map(&:length)
183
+ name_width, verb_width, path_width = widths(routes).zip(header_lengths).map(&:max)
184
+
185
+ routes.map do |r|
186
+ "#{r[:name].rjust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:path].ljust(path_width)} #{r[:reqs]}"
187
+ end
188
+ end
189
+
190
+ def draw_header(routes)
191
+ name_width, verb_width, path_width = widths(routes)
192
+
193
+ "#{"Prefix".rjust(name_width)} #{"Verb".ljust(verb_width)} #{"URI Pattern".ljust(path_width)} Controller#Action"
194
+ end
195
+
196
+ def widths(routes)
197
+ [routes.map { |r| r[:name].length }.max || 0,
198
+ routes.map { |r| r[:verb].length }.max || 0,
199
+ routes.map { |r| r[:path].length }.max || 0]
200
+ end
201
+ end
202
+
203
+ class Expanded < Base
204
+ def section_title(title)
205
+ @buffer << "\n#{"[ #{title} ]"}"
206
+ end
207
+
208
+ def section(routes)
209
+ @buffer << draw_expanded_section(routes)
210
+ end
211
+
212
+ private
213
+
214
+ def draw_expanded_section(routes)
215
+ routes.map.each_with_index do |r, i|
216
+ <<~MESSAGE.chomp
217
+ #{route_header(index: i + 1)}
218
+ Prefix | #{r[:name]}
219
+ Verb | #{r[:verb]}
220
+ URI | #{r[:path]}
221
+ Controller#Action | #{r[:reqs]}
222
+ MESSAGE
223
+ end
224
+ end
225
+
226
+ def route_header(index:)
227
+ console_width = IO.console_size.second
228
+ header_prefix = "--[ Route #{index} ]"
229
+ dash_remainder = [console_width - header_prefix.size, 0].max
230
+
231
+ "#{header_prefix}#{'-' * dash_remainder}"
232
+ end
233
+ end
234
+ end
235
+
236
+ class HtmlTableFormatter
237
+ def initialize(view)
238
+ @view = view
239
+ @buffer = []
240
+ end
241
+
242
+ def section_title(title)
243
+ @buffer << %(<tr><th colspan="4">#{title}</th></tr>)
244
+ end
245
+
246
+ def section(routes)
247
+ @buffer << @view.render(partial: "routes/route", collection: routes)
248
+ end
249
+
250
+ # The header is part of the HTML page, so we don't construct it here.
251
+ def header(routes)
252
+ end
253
+
254
+ def no_routes(*)
255
+ @buffer << <<~MESSAGE
256
+ <p>You don't have any routes defined!</p>
257
+ <ul>
258
+ <li>Please add some routes in <tt>config/routes.rb</tt>.</li>
259
+ <li>
260
+ For more information about routes, please see the Rails guide
261
+ <a href="https://guides.rubyonrails.org/routing.html">Rails Routing from the Outside In</a>.
262
+ </li>
263
+ </ul>
264
+ MESSAGE
265
+ end
266
+
267
+ def result
268
+ @view.raw @view.render(layout: "routes/table") {
269
+ @view.raw @buffer.join("\n")
270
+ }
271
+ end
272
+ end
273
+ end
274
+ end