actionpack 3.2.22.5 → 5.2.4
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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +279 -603
- data/MIT-LICENSE +1 -1
- data/README.rdoc +13 -297
- data/lib/abstract_controller/asset_paths.rb +4 -2
- data/lib/abstract_controller/base.rb +82 -52
- data/lib/abstract_controller/caching/fragments.rb +166 -0
- data/lib/abstract_controller/caching.rb +66 -0
- data/lib/abstract_controller/callbacks.rb +117 -103
- data/lib/abstract_controller/collector.rb +18 -7
- data/lib/abstract_controller/error.rb +6 -0
- data/lib/abstract_controller/helpers.rb +65 -38
- data/lib/abstract_controller/logger.rb +3 -2
- data/lib/abstract_controller/railties/routes_helpers.rb +5 -3
- data/lib/abstract_controller/rendering.rb +77 -129
- data/lib/abstract_controller/translation.rb +21 -3
- data/lib/abstract_controller/url_for.rb +9 -7
- data/lib/abstract_controller.rb +12 -13
- data/lib/action_controller/api/api_rendering.rb +16 -0
- data/lib/action_controller/api.rb +149 -0
- data/lib/action_controller/base.rb +81 -40
- data/lib/action_controller/caching.rb +22 -62
- data/lib/action_controller/form_builder.rb +50 -0
- data/lib/action_controller/log_subscriber.rb +30 -18
- data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
- data/lib/action_controller/metal/conditional_get.rb +190 -47
- data/lib/action_controller/metal/content_security_policy.rb +52 -0
- data/lib/action_controller/metal/cookies.rb +3 -3
- data/lib/action_controller/metal/data_streaming.rb +40 -65
- data/lib/action_controller/metal/etag_with_flash.rb +18 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +57 -0
- data/lib/action_controller/metal/exceptions.rb +19 -12
- data/lib/action_controller/metal/flash.rb +42 -9
- data/lib/action_controller/metal/force_ssl.rb +79 -19
- data/lib/action_controller/metal/head.rb +35 -10
- data/lib/action_controller/metal/helpers.rb +31 -21
- data/lib/action_controller/metal/http_authentication.rb +182 -134
- data/lib/action_controller/metal/implicit_render.rb +62 -8
- data/lib/action_controller/metal/instrumentation.rb +28 -26
- data/lib/action_controller/metal/live.rb +312 -0
- data/lib/action_controller/metal/mime_responds.rb +159 -163
- data/lib/action_controller/metal/parameter_encoding.rb +51 -0
- data/lib/action_controller/metal/params_wrapper.rb +146 -93
- data/lib/action_controller/metal/redirecting.rb +80 -56
- data/lib/action_controller/metal/renderers.rb +119 -47
- data/lib/action_controller/metal/rendering.rb +89 -32
- data/lib/action_controller/metal/request_forgery_protection.rb +373 -41
- data/lib/action_controller/metal/rescue.rb +9 -16
- data/lib/action_controller/metal/streaming.rb +39 -45
- data/lib/action_controller/metal/strong_parameters.rb +1086 -0
- data/lib/action_controller/metal/testing.rb +8 -29
- data/lib/action_controller/metal/url_for.rb +43 -32
- data/lib/action_controller/metal.rb +112 -106
- data/lib/action_controller/railtie.rb +56 -18
- data/lib/action_controller/railties/helpers.rb +24 -0
- data/lib/action_controller/renderer.rb +117 -0
- data/lib/action_controller/template_assertions.rb +11 -0
- data/lib/action_controller/test_case.rb +402 -347
- data/lib/action_controller.rb +31 -30
- data/lib/action_dispatch/http/cache.rb +133 -34
- data/lib/action_dispatch/http/content_security_policy.rb +272 -0
- data/lib/action_dispatch/http/filter_parameters.rb +40 -24
- data/lib/action_dispatch/http/filter_redirect.rb +37 -0
- data/lib/action_dispatch/http/headers.rb +117 -16
- data/lib/action_dispatch/http/mime_negotiation.rb +98 -33
- data/lib/action_dispatch/http/mime_type.rb +198 -146
- data/lib/action_dispatch/http/mime_types.rb +22 -7
- data/lib/action_dispatch/http/parameter_filter.rb +61 -49
- data/lib/action_dispatch/http/parameters.rb +94 -51
- data/lib/action_dispatch/http/rack_cache.rb +4 -3
- data/lib/action_dispatch/http/request.rb +262 -117
- data/lib/action_dispatch/http/response.rb +400 -86
- data/lib/action_dispatch/http/upload.rb +66 -29
- data/lib/action_dispatch/http/url.rb +232 -60
- data/lib/action_dispatch/journey/formatter.rb +189 -0
- data/lib/action_dispatch/journey/gtg/builder.rb +164 -0
- data/lib/action_dispatch/journey/gtg/simulator.rb +41 -0
- data/lib/action_dispatch/journey/gtg/transition_table.rb +158 -0
- data/lib/action_dispatch/journey/nfa/builder.rb +78 -0
- data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
- data/lib/action_dispatch/journey/nfa/simulator.rb +49 -0
- data/lib/action_dispatch/journey/nfa/transition_table.rb +120 -0
- data/lib/action_dispatch/journey/nodes/node.rb +140 -0
- data/lib/action_dispatch/journey/parser.rb +199 -0
- data/lib/action_dispatch/journey/parser.y +50 -0
- data/lib/action_dispatch/journey/parser_extras.rb +31 -0
- data/lib/action_dispatch/journey/path/pattern.rb +199 -0
- data/lib/action_dispatch/journey/route.rb +203 -0
- data/lib/action_dispatch/journey/router/utils.rb +102 -0
- data/lib/action_dispatch/journey/router.rb +156 -0
- data/lib/action_dispatch/journey/routes.rb +82 -0
- data/lib/action_dispatch/journey/scanner.rb +64 -0
- data/lib/action_dispatch/journey/visitors.rb +268 -0
- data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
- data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
- data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
- data/lib/action_dispatch/journey.rb +7 -0
- data/lib/action_dispatch/middleware/callbacks.rb +17 -13
- data/lib/action_dispatch/middleware/cookies.rb +494 -162
- data/lib/action_dispatch/middleware/debug_exceptions.rb +176 -53
- data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +103 -38
- data/lib/action_dispatch/middleware/executor.rb +21 -0
- data/lib/action_dispatch/middleware/flash.rb +128 -91
- data/lib/action_dispatch/middleware/public_exceptions.rb +43 -16
- data/lib/action_dispatch/middleware/reloader.rb +6 -83
- data/lib/action_dispatch/middleware/remote_ip.rb +151 -49
- data/lib/action_dispatch/middleware/request_id.rb +19 -15
- data/lib/action_dispatch/middleware/session/abstract_store.rb +38 -34
- data/lib/action_dispatch/middleware/session/cache_store.rb +14 -9
- data/lib/action_dispatch/middleware/session/cookie_store.rb +94 -44
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +15 -4
- data/lib/action_dispatch/middleware/show_exceptions.rb +36 -61
- data/lib/action_dispatch/middleware/ssl.rb +150 -0
- data/lib/action_dispatch/middleware/stack.rb +33 -41
- data/lib/action_dispatch/middleware/static.rb +92 -48
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +22 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +27 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
- data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +134 -5
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
- data/lib/action_dispatch/railtie.rb +29 -8
- data/lib/action_dispatch/request/session.rb +234 -0
- data/lib/action_dispatch/request/utils.rb +78 -0
- data/lib/action_dispatch/routing/endpoint.rb +17 -0
- data/lib/action_dispatch/routing/inspector.rb +225 -0
- data/lib/action_dispatch/routing/mapper.rb +1329 -582
- data/lib/action_dispatch/routing/polymorphic_routes.rb +237 -94
- data/lib/action_dispatch/routing/redirection.rb +120 -50
- data/lib/action_dispatch/routing/route_set.rb +545 -322
- data/lib/action_dispatch/routing/routes_proxy.rb +37 -7
- data/lib/action_dispatch/routing/url_for.rb +103 -34
- data/lib/action_dispatch/routing.rb +66 -99
- data/lib/action_dispatch/system_test_case.rb +147 -0
- data/lib/action_dispatch/system_testing/browser.rb +49 -0
- data/lib/action_dispatch/system_testing/driver.rb +59 -0
- data/lib/action_dispatch/system_testing/server.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
- data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
- data/lib/action_dispatch/testing/assertion_response.rb +47 -0
- data/lib/action_dispatch/testing/assertions/response.rb +53 -42
- data/lib/action_dispatch/testing/assertions/routing.rb +79 -74
- data/lib/action_dispatch/testing/assertions.rb +15 -9
- data/lib/action_dispatch/testing/integration.rb +361 -207
- data/lib/action_dispatch/testing/request_encoder.rb +55 -0
- data/lib/action_dispatch/testing/test_process.rb +28 -19
- data/lib/action_dispatch/testing/test_request.rb +30 -33
- data/lib/action_dispatch/testing/test_response.rb +35 -11
- data/lib/action_dispatch.rb +42 -32
- data/lib/action_pack/gem_version.rb +17 -0
- data/lib/action_pack/version.rb +7 -7
- data/lib/action_pack.rb +4 -2
- metadata +116 -175
- data/lib/abstract_controller/layouts.rb +0 -423
- data/lib/abstract_controller/view_paths.rb +0 -96
- data/lib/action_controller/caching/actions.rb +0 -185
- data/lib/action_controller/caching/fragments.rb +0 -127
- data/lib/action_controller/caching/pages.rb +0 -187
- data/lib/action_controller/caching/sweeping.rb +0 -97
- data/lib/action_controller/deprecated/integration_test.rb +0 -2
- data/lib/action_controller/deprecated/performance_test.rb +0 -1
- data/lib/action_controller/deprecated.rb +0 -3
- data/lib/action_controller/metal/compatibility.rb +0 -65
- data/lib/action_controller/metal/hide_actions.rb +0 -41
- data/lib/action_controller/metal/rack_delegation.rb +0 -26
- data/lib/action_controller/metal/responder.rb +0 -286
- data/lib/action_controller/metal/session_management.rb +0 -14
- data/lib/action_controller/middleware.rb +0 -39
- data/lib/action_controller/railties/paths.rb +0 -25
- data/lib/action_controller/record_identifier.rb +0 -85
- data/lib/action_controller/vendor/html-scanner/html/document.rb +0 -68
- data/lib/action_controller/vendor/html-scanner/html/node.rb +0 -532
- data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +0 -177
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +0 -830
- data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +0 -107
- data/lib/action_controller/vendor/html-scanner/html/version.rb +0 -11
- data/lib/action_controller/vendor/html-scanner.rb +0 -20
- data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
- data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
- data/lib/action_dispatch/middleware/head.rb +0 -18
- data/lib/action_dispatch/middleware/params_parser.rb +0 -75
- data/lib/action_dispatch/middleware/rescue.rb +0 -26
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +0 -31
- data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -26
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +0 -10
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -2
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +0 -15
- data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -17
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +0 -2
- data/lib/action_dispatch/testing/assertions/dom.rb +0 -37
- data/lib/action_dispatch/testing/assertions/selector.rb +0 -435
- data/lib/action_dispatch/testing/assertions/tag.rb +0 -138
- data/lib/action_dispatch/testing/performance_test.rb +0 -10
- data/lib/action_view/asset_paths.rb +0 -142
- data/lib/action_view/base.rb +0 -220
- data/lib/action_view/buffers.rb +0 -43
- data/lib/action_view/context.rb +0 -36
- data/lib/action_view/flows.rb +0 -79
- data/lib/action_view/helpers/active_model_helper.rb +0 -50
- data/lib/action_view/helpers/asset_paths.rb +0 -7
- data/lib/action_view/helpers/asset_tag_helper.rb +0 -457
- data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
- data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
- data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
- data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
- data/lib/action_view/helpers/atom_feed_helper.rb +0 -200
- data/lib/action_view/helpers/cache_helper.rb +0 -64
- data/lib/action_view/helpers/capture_helper.rb +0 -203
- data/lib/action_view/helpers/controller_helper.rb +0 -25
- data/lib/action_view/helpers/csrf_helper.rb +0 -32
- data/lib/action_view/helpers/date_helper.rb +0 -1062
- data/lib/action_view/helpers/debug_helper.rb +0 -40
- data/lib/action_view/helpers/form_helper.rb +0 -1486
- data/lib/action_view/helpers/form_options_helper.rb +0 -658
- data/lib/action_view/helpers/form_tag_helper.rb +0 -685
- data/lib/action_view/helpers/javascript_helper.rb +0 -110
- data/lib/action_view/helpers/number_helper.rb +0 -622
- data/lib/action_view/helpers/output_safety_helper.rb +0 -38
- data/lib/action_view/helpers/record_tag_helper.rb +0 -111
- data/lib/action_view/helpers/rendering_helper.rb +0 -92
- data/lib/action_view/helpers/sanitize_helper.rb +0 -259
- data/lib/action_view/helpers/tag_helper.rb +0 -167
- data/lib/action_view/helpers/text_helper.rb +0 -426
- data/lib/action_view/helpers/translation_helper.rb +0 -91
- data/lib/action_view/helpers/url_helper.rb +0 -693
- data/lib/action_view/helpers.rb +0 -60
- data/lib/action_view/locale/en.yml +0 -160
- data/lib/action_view/log_subscriber.rb +0 -28
- data/lib/action_view/lookup_context.rb +0 -258
- data/lib/action_view/path_set.rb +0 -101
- data/lib/action_view/railtie.rb +0 -55
- data/lib/action_view/renderer/abstract_renderer.rb +0 -41
- data/lib/action_view/renderer/partial_renderer.rb +0 -415
- data/lib/action_view/renderer/renderer.rb +0 -61
- data/lib/action_view/renderer/streaming_template_renderer.rb +0 -106
- data/lib/action_view/renderer/template_renderer.rb +0 -95
- data/lib/action_view/template/error.rb +0 -128
- data/lib/action_view/template/handlers/builder.rb +0 -26
- data/lib/action_view/template/handlers/erb.rb +0 -125
- data/lib/action_view/template/handlers.rb +0 -50
- data/lib/action_view/template/resolver.rb +0 -298
- data/lib/action_view/template/text.rb +0 -30
- data/lib/action_view/template.rb +0 -337
- data/lib/action_view/test_case.rb +0 -246
- data/lib/action_view/testing/resolvers.rb +0 -49
- data/lib/action_view.rb +0 -84
- data/lib/sprockets/assets.rake +0 -99
- data/lib/sprockets/bootstrap.rb +0 -37
- data/lib/sprockets/compressors.rb +0 -83
- data/lib/sprockets/helpers/isolated_helper.rb +0 -13
- data/lib/sprockets/helpers/rails_helper.rb +0 -182
- data/lib/sprockets/helpers.rb +0 -6
- data/lib/sprockets/railtie.rb +0 -62
- data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,127 +1,134 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "action_dispatch/journey"
|
4
|
+
require "active_support/core_ext/object/to_query"
|
5
|
+
require "active_support/core_ext/hash/slice"
|
6
|
+
require "active_support/core_ext/module/redefine_method"
|
7
|
+
require "active_support/core_ext/module/remove_method"
|
8
|
+
require "active_support/core_ext/array/extract_options"
|
9
|
+
require "action_controller/metal/exceptions"
|
10
|
+
require "action_dispatch/http/request"
|
11
|
+
require "action_dispatch/routing/endpoint"
|
8
12
|
|
9
13
|
module ActionDispatch
|
10
14
|
module Routing
|
11
|
-
|
15
|
+
# :stopdoc:
|
16
|
+
class RouteSet
|
12
17
|
# Since the router holds references to many parts of the system
|
13
18
|
# like engines, controllers and the application itself, inspecting
|
14
19
|
# the route set can actually be really slow, therefore we default
|
15
20
|
# alias inspect to to_s.
|
16
21
|
alias inspect to_s
|
17
22
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
def initialize(options={})
|
22
|
-
@defaults = options[:defaults]
|
23
|
-
@glob_param = options.delete(:glob)
|
24
|
-
@controllers = {}
|
25
|
-
end
|
26
|
-
|
27
|
-
def call(env)
|
28
|
-
params = env[PARAMETERS_KEY]
|
29
|
-
prepare_params!(params)
|
30
|
-
|
31
|
-
# Just raise undefined constant errors if a controller was specified as default.
|
32
|
-
unless controller = controller(params, @defaults.key?(:controller))
|
33
|
-
return [404, {'X-Cascade' => 'pass'}, []]
|
34
|
-
end
|
35
|
-
|
36
|
-
dispatch(controller, params[:action], env)
|
23
|
+
class Dispatcher < Routing::Endpoint
|
24
|
+
def initialize(raise_on_name_error)
|
25
|
+
@raise_on_name_error = raise_on_name_error
|
37
26
|
end
|
38
27
|
|
39
|
-
def
|
40
|
-
normalize_controller!(params)
|
41
|
-
merge_default_action!(params)
|
42
|
-
split_glob_param!(params) if @glob_param
|
43
|
-
end
|
28
|
+
def dispatcher?; true; end
|
44
29
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
30
|
+
def serve(req)
|
31
|
+
params = req.path_parameters
|
32
|
+
controller = controller req
|
33
|
+
res = controller.make_response! req
|
34
|
+
dispatch(controller, params[:action], req, res)
|
35
|
+
rescue ActionController::RoutingError
|
36
|
+
if @raise_on_name_error
|
37
|
+
raise
|
38
|
+
else
|
39
|
+
return [404, { "X-Cascade" => "pass" }, []]
|
55
40
|
end
|
56
|
-
rescue NameError => e
|
57
|
-
raise ActionController::RoutingError, e.message, e.backtrace if default_controller
|
58
41
|
end
|
59
42
|
|
60
43
|
private
|
61
44
|
|
62
|
-
def
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
controller = @controllers[controller_param] =
|
67
|
-
ActiveSupport::Dependencies.reference(controller_name)
|
68
|
-
end
|
69
|
-
controller.get(controller_name)
|
45
|
+
def controller(req)
|
46
|
+
req.controller_class
|
47
|
+
rescue NameError => e
|
48
|
+
raise ActionController::RoutingError, e.message, e.backtrace
|
70
49
|
end
|
71
50
|
|
72
|
-
def dispatch(controller, action,
|
73
|
-
controller.
|
51
|
+
def dispatch(controller, action, req, res)
|
52
|
+
controller.dispatch(action, req, res)
|
74
53
|
end
|
54
|
+
end
|
75
55
|
|
76
|
-
|
77
|
-
|
56
|
+
class StaticDispatcher < Dispatcher
|
57
|
+
def initialize(controller_class)
|
58
|
+
super(false)
|
59
|
+
@controller_class = controller_class
|
78
60
|
end
|
79
61
|
|
80
|
-
|
81
|
-
params[:action] ||= 'index'
|
82
|
-
end
|
62
|
+
private
|
83
63
|
|
84
|
-
|
85
|
-
params[@glob_param] = params[@glob_param].split('/').map { |v| URI.parser.unescape(v) }
|
86
|
-
end
|
64
|
+
def controller(_); @controller_class; end
|
87
65
|
end
|
88
66
|
|
89
67
|
# A NamedRouteCollection instance is a collection of named routes, and also
|
90
68
|
# maintains an anonymous module that can be used to install helpers for the
|
91
69
|
# named routes.
|
92
|
-
class NamedRouteCollection
|
70
|
+
class NamedRouteCollection
|
93
71
|
include Enumerable
|
94
|
-
attr_reader :routes, :
|
72
|
+
attr_reader :routes, :url_helpers_module, :path_helpers_module
|
73
|
+
private :routes
|
95
74
|
|
96
75
|
def initialize
|
97
76
|
@routes = {}
|
98
|
-
@
|
77
|
+
@path_helpers = Set.new
|
78
|
+
@url_helpers = Set.new
|
79
|
+
@url_helpers_module = Module.new
|
80
|
+
@path_helpers_module = Module.new
|
81
|
+
end
|
99
82
|
|
100
|
-
|
83
|
+
def route_defined?(name)
|
84
|
+
key = name.to_sym
|
85
|
+
@path_helpers.include?(key) || @url_helpers.include?(key)
|
101
86
|
end
|
102
87
|
|
103
88
|
def helper_names
|
104
|
-
|
89
|
+
@path_helpers.map(&:to_s) + @url_helpers.map(&:to_s)
|
105
90
|
end
|
106
91
|
|
107
92
|
def clear!
|
108
|
-
@
|
109
|
-
@
|
93
|
+
@path_helpers.each do |helper|
|
94
|
+
@path_helpers_module.send :remove_method, helper
|
95
|
+
end
|
96
|
+
|
97
|
+
@url_helpers.each do |helper|
|
98
|
+
@url_helpers_module.send :remove_method, helper
|
110
99
|
end
|
111
100
|
|
112
101
|
@routes.clear
|
113
|
-
@
|
102
|
+
@path_helpers.clear
|
103
|
+
@url_helpers.clear
|
114
104
|
end
|
115
105
|
|
116
106
|
def add(name, route)
|
117
|
-
|
118
|
-
|
107
|
+
key = name.to_sym
|
108
|
+
path_name = :"#{name}_path"
|
109
|
+
url_name = :"#{name}_url"
|
110
|
+
|
111
|
+
if routes.key? key
|
112
|
+
@path_helpers_module.send :undef_method, path_name
|
113
|
+
@url_helpers_module.send :undef_method, url_name
|
114
|
+
end
|
115
|
+
routes[key] = route
|
116
|
+
define_url_helper @path_helpers_module, route, path_name, route.defaults, name, PATH
|
117
|
+
define_url_helper @url_helpers_module, route, url_name, route.defaults, name, UNKNOWN
|
118
|
+
|
119
|
+
@path_helpers << path_name
|
120
|
+
@url_helpers << url_name
|
119
121
|
end
|
120
122
|
|
121
123
|
def get(name)
|
122
124
|
routes[name.to_sym]
|
123
125
|
end
|
124
126
|
|
127
|
+
def key?(name)
|
128
|
+
return unless name
|
129
|
+
routes.key? name.to_sym
|
130
|
+
end
|
131
|
+
|
125
132
|
alias []= add
|
126
133
|
alias [] get
|
127
134
|
alias clear clear!
|
@@ -139,125 +146,269 @@ module ActionDispatch
|
|
139
146
|
routes.length
|
140
147
|
end
|
141
148
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
149
|
+
# Given a +name+, defines name_path and name_url helpers.
|
150
|
+
# Used by 'direct', 'resolve', and 'polymorphic' route helpers.
|
151
|
+
def add_url_helper(name, defaults, &block)
|
152
|
+
helper = CustomUrlHelper.new(name, defaults, &block)
|
153
|
+
path_name = :"#{name}_path"
|
154
|
+
url_name = :"#{name}_url"
|
155
|
+
|
156
|
+
@path_helpers_module.module_eval do
|
157
|
+
define_method(path_name) do |*args|
|
158
|
+
helper.call(self, args, true)
|
159
|
+
end
|
147
160
|
end
|
148
|
-
end
|
149
161
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
162
|
+
@url_helpers_module.module_eval do
|
163
|
+
define_method(url_name) do |*args|
|
164
|
+
helper.call(self, args, false)
|
165
|
+
end
|
154
166
|
end
|
167
|
+
|
168
|
+
@path_helpers << path_name
|
169
|
+
@url_helpers << url_name
|
170
|
+
|
171
|
+
self
|
155
172
|
end
|
156
173
|
|
157
|
-
|
158
|
-
def
|
159
|
-
|
174
|
+
class UrlHelper
|
175
|
+
def self.create(route, options, route_name, url_strategy)
|
176
|
+
if optimize_helper?(route)
|
177
|
+
OptimizedUrlHelper.new(route, options, route_name, url_strategy)
|
178
|
+
else
|
179
|
+
new route, options, route_name, url_strategy
|
180
|
+
end
|
160
181
|
end
|
161
182
|
|
162
|
-
def
|
163
|
-
|
183
|
+
def self.optimize_helper?(route)
|
184
|
+
!route.glob? && route.path.requirements.empty?
|
164
185
|
end
|
165
186
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
187
|
+
attr_reader :url_strategy, :route_name
|
188
|
+
|
189
|
+
class OptimizedUrlHelper < UrlHelper
|
190
|
+
attr_reader :arg_size
|
191
|
+
|
192
|
+
def initialize(route, options, route_name, url_strategy)
|
193
|
+
super
|
194
|
+
@required_parts = @route.required_parts
|
195
|
+
@arg_size = @required_parts.size
|
171
196
|
end
|
172
|
-
end
|
173
197
|
|
174
|
-
|
175
|
-
|
198
|
+
def call(t, args, inner_options)
|
199
|
+
if args.size == arg_size && !inner_options && optimize_routes_generation?(t)
|
200
|
+
options = t.url_options.merge @options
|
201
|
+
options[:path] = optimized_helper(args)
|
176
202
|
|
177
|
-
|
178
|
-
|
179
|
-
remove_possible_method :#{selector}
|
180
|
-
def #{selector}(*args)
|
181
|
-
options = args.extract_options!
|
182
|
-
result = #{options.inspect}
|
203
|
+
original_script_name = options.delete(:original_script_name)
|
204
|
+
script_name = t._routes.find_script_name(options)
|
183
205
|
|
184
|
-
if
|
185
|
-
|
186
|
-
result[:_positional_keys] = #{route.segment_keys.inspect}
|
206
|
+
if original_script_name
|
207
|
+
script_name = original_script_name + script_name
|
187
208
|
end
|
188
209
|
|
189
|
-
|
210
|
+
options[:script_name] = script_name
|
211
|
+
|
212
|
+
url_strategy.call options
|
213
|
+
else
|
214
|
+
super
|
190
215
|
end
|
191
|
-
|
192
|
-
|
193
|
-
|
216
|
+
end
|
217
|
+
|
218
|
+
private
|
219
|
+
|
220
|
+
def optimized_helper(args)
|
221
|
+
params = parameterize_args(args) do
|
222
|
+
raise_generation_error(args)
|
223
|
+
end
|
224
|
+
|
225
|
+
@route.format params
|
226
|
+
end
|
227
|
+
|
228
|
+
def optimize_routes_generation?(t)
|
229
|
+
t.send(:optimize_routes_generation?)
|
230
|
+
end
|
231
|
+
|
232
|
+
def parameterize_args(args)
|
233
|
+
params = {}
|
234
|
+
@arg_size.times { |i|
|
235
|
+
key = @required_parts[i]
|
236
|
+
value = args[i].to_param
|
237
|
+
yield key if value.nil? || value.empty?
|
238
|
+
params[key] = value
|
239
|
+
}
|
240
|
+
params
|
241
|
+
end
|
242
|
+
|
243
|
+
def raise_generation_error(args)
|
244
|
+
missing_keys = []
|
245
|
+
params = parameterize_args(args) { |missing_key|
|
246
|
+
missing_keys << missing_key
|
247
|
+
}
|
248
|
+
constraints = Hash[@route.requirements.merge(params).sort_by { |k, v| k.to_s }]
|
249
|
+
message = "No route matches #{constraints.inspect}".dup
|
250
|
+
message << ", missing required keys: #{missing_keys.sort.inspect}"
|
251
|
+
|
252
|
+
raise ActionController::UrlGenerationError, message
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def initialize(route, options, route_name, url_strategy)
|
257
|
+
@options = options
|
258
|
+
@segment_keys = route.segment_keys.uniq
|
259
|
+
@route = route
|
260
|
+
@url_strategy = url_strategy
|
261
|
+
@route_name = route_name
|
194
262
|
end
|
195
263
|
|
196
|
-
|
264
|
+
def call(t, args, inner_options)
|
265
|
+
controller_options = t.url_options
|
266
|
+
options = controller_options.merge @options
|
267
|
+
hash = handle_positional_args(controller_options,
|
268
|
+
inner_options || {},
|
269
|
+
args,
|
270
|
+
options,
|
271
|
+
@segment_keys)
|
272
|
+
|
273
|
+
t._routes.url_for(hash, route_name, url_strategy)
|
274
|
+
end
|
275
|
+
|
276
|
+
def handle_positional_args(controller_options, inner_options, args, result, path_params)
|
277
|
+
if args.size > 0
|
278
|
+
# take format into account
|
279
|
+
if path_params.include?(:format)
|
280
|
+
path_params_size = path_params.size - 1
|
281
|
+
else
|
282
|
+
path_params_size = path_params.size
|
283
|
+
end
|
284
|
+
|
285
|
+
if args.size < path_params_size
|
286
|
+
path_params -= controller_options.keys
|
287
|
+
path_params -= result.keys
|
288
|
+
else
|
289
|
+
path_params = path_params.dup
|
290
|
+
end
|
291
|
+
inner_options.each_key do |key|
|
292
|
+
path_params.delete(key)
|
293
|
+
end
|
294
|
+
|
295
|
+
args.each_with_index do |arg, index|
|
296
|
+
param = path_params[index]
|
297
|
+
result[param] = arg if param
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
result.merge!(inner_options)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
private
|
306
|
+
# Create a URL helper allowing ordered parameters to be associated
|
197
307
|
# with corresponding dynamic segments, so you can do:
|
198
308
|
#
|
199
309
|
# foo_url(bar, baz, bang)
|
200
310
|
#
|
201
311
|
# Instead of:
|
202
312
|
#
|
203
|
-
# foo_url(:
|
313
|
+
# foo_url(bar: bar, baz: baz, bang: bang)
|
204
314
|
#
|
205
315
|
# Also allow options hash, so you can do:
|
206
316
|
#
|
207
|
-
# foo_url(bar, baz, bang, :
|
317
|
+
# foo_url(bar, baz, bang, sort_by: 'baz')
|
208
318
|
#
|
209
|
-
def define_url_helper(route, name,
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
319
|
+
def define_url_helper(mod, route, name, opts, route_key, url_strategy)
|
320
|
+
helper = UrlHelper.create(route, opts, route_key, url_strategy)
|
321
|
+
mod.module_eval do
|
322
|
+
define_method(name) do |*args|
|
323
|
+
last = args.last
|
324
|
+
options = \
|
325
|
+
case last
|
326
|
+
when Hash
|
327
|
+
args.pop
|
328
|
+
when ActionController::Parameters
|
329
|
+
args.pop.to_h
|
330
|
+
end
|
331
|
+
helper.call self, args, options
|
217
332
|
end
|
218
|
-
|
219
|
-
helpers << selector
|
333
|
+
end
|
220
334
|
end
|
221
335
|
end
|
222
336
|
|
337
|
+
# strategy for building urls to send to the client
|
338
|
+
PATH = ->(options) { ActionDispatch::Http::URL.path_for(options) }
|
339
|
+
UNKNOWN = ->(options) { ActionDispatch::Http::URL.url_for(options) }
|
340
|
+
|
223
341
|
attr_accessor :formatter, :set, :named_routes, :default_scope, :router
|
224
342
|
attr_accessor :disable_clear_and_finalize, :resources_path_names
|
225
|
-
attr_accessor :default_url_options
|
343
|
+
attr_accessor :default_url_options
|
344
|
+
attr_reader :env_key, :polymorphic_mappings
|
226
345
|
|
227
346
|
alias :routes :set
|
228
347
|
|
229
348
|
def self.default_resources_path_names
|
230
|
-
{ :
|
349
|
+
{ new: "new", edit: "edit" }
|
231
350
|
end
|
232
351
|
|
233
|
-
def
|
234
|
-
|
235
|
-
|
236
|
-
|
352
|
+
def self.new_with_config(config)
|
353
|
+
route_set_config = DEFAULT_CONFIG
|
354
|
+
|
355
|
+
# engines apparently don't have this set
|
356
|
+
if config.respond_to? :relative_url_root
|
357
|
+
route_set_config.relative_url_root = config.relative_url_root
|
358
|
+
end
|
359
|
+
|
360
|
+
if config.respond_to? :api_only
|
361
|
+
route_set_config.api_only = config.api_only
|
362
|
+
end
|
237
363
|
|
238
|
-
|
239
|
-
|
364
|
+
new route_set_config
|
365
|
+
end
|
366
|
+
|
367
|
+
Config = Struct.new :relative_url_root, :api_only
|
240
368
|
|
241
|
-
|
242
|
-
@valid_conditions[m.to_sym] = true
|
243
|
-
}
|
244
|
-
@valid_conditions[:controller] = true
|
245
|
-
@valid_conditions[:action] = true
|
369
|
+
DEFAULT_CONFIG = Config.new(nil, false)
|
246
370
|
|
247
|
-
|
371
|
+
def initialize(config = DEFAULT_CONFIG)
|
372
|
+
self.named_routes = NamedRouteCollection.new
|
373
|
+
self.resources_path_names = self.class.default_resources_path_names
|
374
|
+
self.default_url_options = {}
|
248
375
|
|
376
|
+
@config = config
|
249
377
|
@append = []
|
250
378
|
@prepend = []
|
251
379
|
@disable_clear_and_finalize = false
|
252
380
|
@finalized = false
|
381
|
+
@env_key = "ROUTES_#{object_id}_SCRIPT_NAME".freeze
|
253
382
|
|
254
383
|
@set = Journey::Routes.new
|
255
|
-
@router = Journey::Router.new
|
256
|
-
|
257
|
-
|
258
|
-
@formatter = Journey::Formatter.new @set
|
384
|
+
@router = Journey::Router.new @set
|
385
|
+
@formatter = Journey::Formatter.new self
|
386
|
+
@polymorphic_mappings = {}
|
259
387
|
end
|
260
388
|
|
389
|
+
def eager_load!
|
390
|
+
router.eager_load!
|
391
|
+
routes.each(&:eager_load!)
|
392
|
+
nil
|
393
|
+
end
|
394
|
+
|
395
|
+
def relative_url_root
|
396
|
+
@config.relative_url_root
|
397
|
+
end
|
398
|
+
|
399
|
+
def api_only?
|
400
|
+
@config.api_only
|
401
|
+
end
|
402
|
+
|
403
|
+
def request_class
|
404
|
+
ActionDispatch::Request
|
405
|
+
end
|
406
|
+
|
407
|
+
def make_request(env)
|
408
|
+
request_class.new env
|
409
|
+
end
|
410
|
+
private :make_request
|
411
|
+
|
261
412
|
def draw(&block)
|
262
413
|
clear! unless @disable_clear_and_finalize
|
263
414
|
eval_block(block)
|
@@ -274,10 +425,6 @@ module ActionDispatch
|
|
274
425
|
end
|
275
426
|
|
276
427
|
def eval_block(block)
|
277
|
-
if block.arity == 1
|
278
|
-
raise "You are using the old router DSL which has been removed in Rails 3.1. " <<
|
279
|
-
"Please check how to update your routes file at: http://www.engineyard.com/blog/2010/the-lowdown-on-routes-in-rails-3/"
|
280
|
-
end
|
281
428
|
mapper = Mapper.new(self)
|
282
429
|
if default_scope
|
283
430
|
mapper.with_default_scope(default_scope, &block)
|
@@ -285,6 +432,7 @@ module ActionDispatch
|
|
285
432
|
mapper.instance_exec(&block)
|
286
433
|
end
|
287
434
|
end
|
435
|
+
private :eval_block
|
288
436
|
|
289
437
|
def finalize!
|
290
438
|
return if @finalized
|
@@ -297,64 +445,131 @@ module ActionDispatch
|
|
297
445
|
named_routes.clear
|
298
446
|
set.clear
|
299
447
|
formatter.clear
|
448
|
+
@polymorphic_mappings.clear
|
300
449
|
@prepend.each { |blk| eval_block(blk) }
|
301
450
|
end
|
302
451
|
|
303
|
-
def install_helpers(destinations = [ActionController::Base, ActionView::Base], regenerate_code = false)
|
304
|
-
Array(destinations).each { |d| d.module_eval { include Helpers } }
|
305
|
-
named_routes.install(destinations, regenerate_code)
|
306
|
-
end
|
307
|
-
|
308
452
|
module MountedHelpers
|
453
|
+
extend ActiveSupport::Concern
|
454
|
+
include UrlFor
|
309
455
|
end
|
310
456
|
|
457
|
+
# Contains all the mounted helpers across different
|
458
|
+
# engines and the `main_app` helper for the application.
|
459
|
+
# You can include this in your classes if you want to
|
460
|
+
# access routes for other engines.
|
311
461
|
def mounted_helpers
|
312
462
|
MountedHelpers
|
313
463
|
end
|
314
464
|
|
315
|
-
def define_mounted_helper(name)
|
465
|
+
def define_mounted_helper(name, script_namer = nil)
|
316
466
|
return if MountedHelpers.method_defined?(name)
|
317
467
|
|
318
468
|
routes = self
|
469
|
+
helpers = routes.url_helpers
|
470
|
+
|
319
471
|
MountedHelpers.class_eval do
|
320
472
|
define_method "_#{name}" do
|
321
|
-
RoutesProxy.new(routes,
|
473
|
+
RoutesProxy.new(routes, _routes_context, helpers, script_namer)
|
322
474
|
end
|
323
475
|
end
|
324
476
|
|
325
|
-
MountedHelpers.class_eval
|
477
|
+
MountedHelpers.class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
326
478
|
def #{name}
|
327
|
-
|
479
|
+
@_#{name} ||= _#{name}
|
328
480
|
end
|
329
481
|
RUBY
|
330
482
|
end
|
331
483
|
|
332
|
-
def url_helpers
|
333
|
-
|
334
|
-
|
484
|
+
def url_helpers(supports_path = true)
|
485
|
+
routes = self
|
486
|
+
|
487
|
+
Module.new do
|
488
|
+
extend ActiveSupport::Concern
|
489
|
+
include UrlFor
|
335
490
|
|
336
|
-
|
337
|
-
|
491
|
+
# Define url_for in the singleton level so one can do:
|
492
|
+
# Rails.application.routes.url_helpers.url_for(args)
|
493
|
+
proxy_class = Class.new do
|
338
494
|
include UrlFor
|
495
|
+
include routes.named_routes.path_helpers_module
|
496
|
+
include routes.named_routes.url_helpers_module
|
497
|
+
|
498
|
+
attr_reader :_routes
|
499
|
+
|
500
|
+
def initialize(routes)
|
501
|
+
@_routes = routes
|
502
|
+
end
|
503
|
+
|
504
|
+
def optimize_routes_generation?
|
505
|
+
@_routes.optimize_routes_generation?
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
@_proxy = proxy_class.new(routes)
|
339
510
|
|
340
|
-
|
341
|
-
|
342
|
-
|
511
|
+
class << self
|
512
|
+
def url_for(options)
|
513
|
+
@_proxy.url_for(options)
|
343
514
|
end
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
# we can include?
|
348
|
-
# Yes plz - JP
|
349
|
-
included do
|
350
|
-
routes.install_helpers(self)
|
351
|
-
singleton_class.send(:redefine_method, :_routes) { routes }
|
515
|
+
|
516
|
+
def full_url_for(options)
|
517
|
+
@_proxy.full_url_for(options)
|
352
518
|
end
|
353
519
|
|
354
|
-
|
520
|
+
def route_for(name, *args)
|
521
|
+
@_proxy.route_for(name, *args)
|
522
|
+
end
|
523
|
+
|
524
|
+
def optimize_routes_generation?
|
525
|
+
@_proxy.optimize_routes_generation?
|
526
|
+
end
|
527
|
+
|
528
|
+
def polymorphic_url(record_or_hash_or_array, options = {})
|
529
|
+
@_proxy.polymorphic_url(record_or_hash_or_array, options)
|
530
|
+
end
|
531
|
+
|
532
|
+
def polymorphic_path(record_or_hash_or_array, options = {})
|
533
|
+
@_proxy.polymorphic_path(record_or_hash_or_array, options)
|
534
|
+
end
|
535
|
+
|
536
|
+
def _routes; @_proxy._routes; end
|
537
|
+
def url_options; {}; end
|
538
|
+
end
|
539
|
+
|
540
|
+
url_helpers = routes.named_routes.url_helpers_module
|
541
|
+
|
542
|
+
# Make named_routes available in the module singleton
|
543
|
+
# as well, so one can do:
|
544
|
+
# Rails.application.routes.url_helpers.posts_path
|
545
|
+
extend url_helpers
|
546
|
+
|
547
|
+
# Any class that includes this module will get all
|
548
|
+
# named routes...
|
549
|
+
include url_helpers
|
550
|
+
|
551
|
+
if supports_path
|
552
|
+
path_helpers = routes.named_routes.path_helpers_module
|
553
|
+
|
554
|
+
include path_helpers
|
555
|
+
extend path_helpers
|
556
|
+
end
|
557
|
+
|
558
|
+
# plus a singleton class method called _routes ...
|
559
|
+
included do
|
560
|
+
redefine_singleton_method(:_routes) { routes }
|
561
|
+
end
|
562
|
+
|
563
|
+
# And an instance method _routes. Note that
|
564
|
+
# UrlFor (included in this module) add extra
|
565
|
+
# conveniences for working with @_routes.
|
566
|
+
define_method(:_routes) { @_routes || routes }
|
567
|
+
|
568
|
+
define_method(:_generate_paths_by_default) do
|
569
|
+
supports_path
|
355
570
|
end
|
356
571
|
|
357
|
-
|
572
|
+
private :_generate_paths_by_default
|
358
573
|
end
|
359
574
|
end
|
360
575
|
|
@@ -362,90 +577,96 @@ module ActionDispatch
|
|
362
577
|
routes.empty?
|
363
578
|
end
|
364
579
|
|
365
|
-
def add_route(
|
580
|
+
def add_route(mapping, name)
|
366
581
|
raise ArgumentError, "Invalid route name: '#{name}'" unless name.blank? || name.to_s.match(/^[_a-z]\w*$/i)
|
367
582
|
|
368
|
-
|
369
|
-
|
583
|
+
if name && named_routes[name]
|
584
|
+
raise ArgumentError, "Invalid route name, already in use: '#{name}' \n" \
|
585
|
+
"You may have defined two routes with the same name using the `:as` option, or " \
|
586
|
+
"you may be overriding a route already defined by a resource with the same naming. " \
|
587
|
+
"For the latter, you can restrict the routes created with `resources` as explained here: \n" \
|
588
|
+
"http://guides.rubyonrails.org/routing.html#restricting-the-routes-created"
|
589
|
+
end
|
370
590
|
|
371
|
-
route = @set.add_route(
|
591
|
+
route = @set.add_route(name, mapping)
|
372
592
|
named_routes[name] = route if name
|
373
|
-
route
|
374
|
-
end
|
375
|
-
|
376
|
-
def build_path(path, requirements, separators, anchor)
|
377
|
-
strexp = Journey::Router::Strexp.new(
|
378
|
-
path,
|
379
|
-
requirements,
|
380
|
-
SEPARATORS,
|
381
|
-
anchor)
|
382
593
|
|
383
|
-
|
384
|
-
|
385
|
-
|
594
|
+
if route.segment_keys.include?(:controller)
|
595
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
596
|
+
Using a dynamic :controller segment in a route is deprecated and
|
597
|
+
will be removed in Rails 6.0.
|
598
|
+
MSG
|
599
|
+
end
|
386
600
|
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
601
|
+
if route.segment_keys.include?(:action)
|
602
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
603
|
+
Using a dynamic :action segment in a route is deprecated and
|
604
|
+
will be removed in Rails 6.0.
|
605
|
+
MSG
|
606
|
+
end
|
392
607
|
|
393
|
-
|
394
|
-
|
395
|
-
builder.followpos(n).first
|
396
|
-
}.find_all(&:symbol?)
|
608
|
+
route
|
609
|
+
end
|
397
610
|
|
398
|
-
|
399
|
-
|
400
|
-
|
611
|
+
def add_polymorphic_mapping(klass, options, &block)
|
612
|
+
@polymorphic_mappings[klass] = CustomUrlHelper.new(klass, options, &block)
|
613
|
+
end
|
401
614
|
|
402
|
-
|
615
|
+
def add_url_helper(name, options, &block)
|
616
|
+
named_routes.add_url_helper(name, options, &block)
|
403
617
|
end
|
404
|
-
private :build_path
|
405
618
|
|
406
|
-
|
407
|
-
|
619
|
+
class CustomUrlHelper
|
620
|
+
attr_reader :name, :defaults, :block
|
408
621
|
|
409
|
-
|
622
|
+
def initialize(name, defaults, &block)
|
623
|
+
@name = name
|
624
|
+
@defaults = defaults
|
625
|
+
@block = block
|
626
|
+
end
|
627
|
+
|
628
|
+
def call(t, args, only_path = false)
|
629
|
+
options = args.extract_options!
|
630
|
+
url = t.full_url_for(eval_block(t, args, options))
|
410
631
|
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
conditions[:request_method] = %r[^#{verbs.join('|')}$]
|
632
|
+
if only_path
|
633
|
+
"/" + url.partition(%r{(?<!/)/(?!/)}).last
|
634
|
+
else
|
635
|
+
url
|
636
|
+
end
|
417
637
|
end
|
418
|
-
conditions.delete_if { |k,v| !(req_predicates.include?(k) || path_values.include?(k)) }
|
419
638
|
|
420
|
-
|
639
|
+
private
|
640
|
+
def eval_block(t, args, options)
|
641
|
+
t.instance_exec(*args, merge_defaults(options), &block)
|
642
|
+
end
|
643
|
+
|
644
|
+
def merge_defaults(options)
|
645
|
+
defaults ? defaults.merge(options) : options
|
646
|
+
end
|
421
647
|
end
|
422
|
-
private :build_conditions
|
423
648
|
|
424
|
-
class Generator
|
649
|
+
class Generator
|
425
650
|
PARAMETERIZE = lambda do |name, value|
|
426
651
|
if name == :controller
|
427
652
|
value
|
428
|
-
|
429
|
-
value.
|
430
|
-
elsif param = value.to_param
|
431
|
-
param
|
653
|
+
else
|
654
|
+
value.to_param
|
432
655
|
end
|
433
656
|
end
|
434
657
|
|
435
658
|
attr_reader :options, :recall, :set, :named_route
|
436
659
|
|
437
|
-
def initialize(options, recall, set
|
438
|
-
@named_route =
|
439
|
-
@options = options
|
440
|
-
@recall = recall
|
660
|
+
def initialize(named_route, options, recall, set)
|
661
|
+
@named_route = named_route
|
662
|
+
@options = options
|
663
|
+
@recall = recall
|
441
664
|
@set = set
|
442
|
-
@extras = extras
|
443
665
|
|
444
666
|
normalize_options!
|
445
667
|
normalize_controller_action_id!
|
446
668
|
use_relative_controller!
|
447
669
|
normalize_controller!
|
448
|
-
handle_nil_action!
|
449
670
|
end
|
450
671
|
|
451
672
|
def controller
|
@@ -458,10 +679,8 @@ module ActionDispatch
|
|
458
679
|
|
459
680
|
def use_recall_for(key)
|
460
681
|
if @recall[key] && (!@options.key?(key) || @options[key] == @recall[key])
|
461
|
-
if named_route_exists?
|
462
|
-
@options[key] = @recall
|
463
|
-
else
|
464
|
-
@options[key] = @recall.delete(key)
|
682
|
+
if !named_route_exists? || segment_keys.include?(key)
|
683
|
+
@options[key] = @recall[key]
|
465
684
|
end
|
466
685
|
end
|
467
686
|
end
|
@@ -470,19 +689,19 @@ module ActionDispatch
|
|
470
689
|
# If an explicit :controller was given, always make :action explicit
|
471
690
|
# too, so that action expiry works as expected for things like
|
472
691
|
#
|
473
|
-
# generate({:
|
692
|
+
# generate({controller: 'content'}, {controller: 'content', action: 'show'})
|
474
693
|
#
|
475
694
|
# (the above is from the unit tests). In the above case, because the
|
476
695
|
# controller was explicitly given, but no action, the action is implied to
|
477
696
|
# be "index", not the recalled action of "show".
|
478
697
|
|
479
698
|
if options[:controller]
|
480
|
-
options[:action] ||=
|
699
|
+
options[:action] ||= "index"
|
481
700
|
options[:controller] = options[:controller].to_s
|
482
701
|
end
|
483
702
|
|
484
|
-
if options
|
485
|
-
options[:action] = options[:action].to_s
|
703
|
+
if options.key?(:action)
|
704
|
+
options[:action] = (options[:action] || "index").to_s
|
486
705
|
end
|
487
706
|
end
|
488
707
|
|
@@ -492,18 +711,16 @@ module ActionDispatch
|
|
492
711
|
# :controller, :action or :id is not found, don't pull any
|
493
712
|
# more keys from the recall.
|
494
713
|
def normalize_controller_action_id!
|
495
|
-
|
496
|
-
|
497
|
-
use_recall_for(:controller) or return
|
498
|
-
use_recall_for(:action) or return
|
714
|
+
use_recall_for(:controller) || return
|
715
|
+
use_recall_for(:action) || return
|
499
716
|
use_recall_for(:id)
|
500
717
|
end
|
501
718
|
|
502
|
-
# if the current controller is "foo/bar/baz" and :
|
719
|
+
# if the current controller is "foo/bar/baz" and controller: "baz/bat"
|
503
720
|
# is specified, the controller becomes "foo/baz/bat"
|
504
721
|
def use_relative_controller!
|
505
722
|
if !named_route && different_controller? && !controller.start_with?("/")
|
506
|
-
old_parts = current_controller.split(
|
723
|
+
old_parts = current_controller.split("/")
|
507
724
|
size = controller.count("/") + 1
|
508
725
|
parts = old_parts[0...-size] << controller
|
509
726
|
@options[:controller] = parts.join("/")
|
@@ -512,32 +729,19 @@ module ActionDispatch
|
|
512
729
|
|
513
730
|
# Remove leading slashes from controllers
|
514
731
|
def normalize_controller!
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
if options.has_key?(:action) && options[:action].nil?
|
522
|
-
options[:action] = 'index'
|
732
|
+
if controller
|
733
|
+
if controller.start_with?("/".freeze)
|
734
|
+
@options[:controller] = controller[1..-1]
|
735
|
+
else
|
736
|
+
@options[:controller] = controller
|
737
|
+
end
|
523
738
|
end
|
524
|
-
recall[:action] = options.delete(:action) if options[:action] == 'index'
|
525
739
|
end
|
526
740
|
|
741
|
+
# Generates a path from routes, returns [path, params].
|
742
|
+
# If no route is generated the formatter will raise ActionController::UrlGenerationError
|
527
743
|
def generate
|
528
|
-
|
529
|
-
|
530
|
-
raise_routing_error unless path
|
531
|
-
|
532
|
-
return [path, params.keys] if @extras
|
533
|
-
|
534
|
-
[path, params]
|
535
|
-
rescue Journey::Router::RoutingError
|
536
|
-
raise_routing_error
|
537
|
-
end
|
538
|
-
|
539
|
-
def raise_routing_error
|
540
|
-
raise ActionController::RoutingError, "No route matches #{options.inspect}"
|
744
|
+
@set.formatter.generate(named_route, options, recall, PARAMETERIZE)
|
541
745
|
end
|
542
746
|
|
543
747
|
def different_controller?
|
@@ -557,55 +761,83 @@ module ActionDispatch
|
|
557
761
|
|
558
762
|
# Generate the path indicated by the arguments, and return an array of
|
559
763
|
# the keys that were not used to generate it.
|
560
|
-
def extra_keys(options, recall={})
|
764
|
+
def extra_keys(options, recall = {})
|
561
765
|
generate_extras(options, recall).last
|
562
766
|
end
|
563
767
|
|
564
|
-
def generate_extras(options, recall={})
|
565
|
-
|
768
|
+
def generate_extras(options, recall = {})
|
769
|
+
route_key = options.delete :use_route
|
770
|
+
path, params = generate(route_key, options, recall)
|
771
|
+
return path, params.keys
|
566
772
|
end
|
567
773
|
|
568
|
-
def generate(options, recall = {}
|
569
|
-
Generator.new(options, recall, self
|
774
|
+
def generate(route_key, options, recall = {})
|
775
|
+
Generator.new(route_key, options, recall, self).generate
|
570
776
|
end
|
777
|
+
private :generate
|
571
778
|
|
572
779
|
RESERVED_OPTIONS = [:host, :protocol, :port, :subdomain, :domain, :tld_length,
|
573
|
-
:trailing_slash, :anchor, :params, :only_path, :script_name
|
780
|
+
:trailing_slash, :anchor, :params, :only_path, :script_name,
|
781
|
+
:original_script_name, :relative_url_root]
|
574
782
|
|
575
|
-
def
|
576
|
-
|
783
|
+
def optimize_routes_generation?
|
784
|
+
default_url_options.empty?
|
785
|
+
end
|
786
|
+
|
787
|
+
def find_script_name(options)
|
788
|
+
options.delete(:script_name) || find_relative_url_root(options) || ""
|
577
789
|
end
|
578
790
|
|
579
|
-
def
|
580
|
-
|
581
|
-
|
791
|
+
def find_relative_url_root(options)
|
792
|
+
options.delete(:relative_url_root) || relative_url_root
|
793
|
+
end
|
794
|
+
|
795
|
+
def path_for(options, route_name = nil)
|
796
|
+
url_for(options, route_name, PATH)
|
797
|
+
end
|
798
|
+
|
799
|
+
# The +options+ argument must be a hash whose keys are *symbols*.
|
800
|
+
def url_for(options, route_name = nil, url_strategy = UNKNOWN)
|
801
|
+
options = default_url_options.merge options
|
802
|
+
|
803
|
+
user = password = nil
|
582
804
|
|
583
|
-
|
805
|
+
if options[:user] && options[:password]
|
806
|
+
user = options.delete :user
|
807
|
+
password = options.delete :password
|
808
|
+
end
|
809
|
+
|
810
|
+
recall = options.delete(:_recall) { {} }
|
811
|
+
|
812
|
+
original_script_name = options.delete(:original_script_name)
|
813
|
+
script_name = find_script_name options
|
584
814
|
|
585
|
-
|
586
|
-
|
587
|
-
|
815
|
+
if original_script_name
|
816
|
+
script_name = original_script_name + script_name
|
817
|
+
end
|
818
|
+
|
819
|
+
path_options = options.dup
|
820
|
+
RESERVED_OPTIONS.each { |ro| path_options.delete ro }
|
588
821
|
|
589
|
-
path = (
|
822
|
+
path, params = generate(route_name, path_options, recall)
|
590
823
|
|
591
|
-
|
592
|
-
|
824
|
+
if options.key? :params
|
825
|
+
params.merge! options[:params]
|
826
|
+
end
|
593
827
|
|
594
|
-
|
595
|
-
|
596
|
-
|
828
|
+
options[:path] = path
|
829
|
+
options[:script_name] = script_name
|
830
|
+
options[:params] = params
|
831
|
+
options[:user] = user
|
832
|
+
options[:password] = password
|
597
833
|
|
598
|
-
|
599
|
-
:path => path,
|
600
|
-
:params => params,
|
601
|
-
:user => user,
|
602
|
-
:password => password
|
603
|
-
}))
|
834
|
+
url_strategy.call options
|
604
835
|
end
|
605
836
|
|
606
837
|
def call(env)
|
607
|
-
|
608
|
-
|
838
|
+
req = make_request(env)
|
839
|
+
req.path_info = Journey::Router::Utils.normalize_path(req.path_info)
|
840
|
+
@router.serve(req)
|
609
841
|
end
|
610
842
|
|
611
843
|
def recognize_path(path, environment = {})
|
@@ -614,54 +846,45 @@ module ActionDispatch
|
|
614
846
|
extras = environment[:extras] || {}
|
615
847
|
|
616
848
|
begin
|
617
|
-
env = Rack::MockRequest.env_for(path,
|
849
|
+
env = Rack::MockRequest.env_for(path, method: method)
|
618
850
|
rescue URI::InvalidURIError => e
|
619
851
|
raise ActionController::RoutingError, e.message
|
620
852
|
end
|
621
853
|
|
622
|
-
req =
|
623
|
-
|
854
|
+
req = make_request(env)
|
855
|
+
recognize_path_with_request(req, path, extras)
|
856
|
+
end
|
857
|
+
|
858
|
+
def recognize_path_with_request(req, path, extras, raise_on_missing: true)
|
859
|
+
@router.recognize(req) do |route, params|
|
860
|
+
params.merge!(extras)
|
624
861
|
params.each do |key, value|
|
625
862
|
if value.is_a?(String)
|
626
|
-
value = value.dup.force_encoding(Encoding::BINARY)
|
863
|
+
value = value.dup.force_encoding(Encoding::BINARY)
|
627
864
|
params[key] = URI.parser.unescape(value)
|
628
865
|
end
|
629
866
|
end
|
867
|
+
req.path_parameters = params
|
868
|
+
app = route.app
|
869
|
+
if app.matches?(req) && app.dispatcher?
|
870
|
+
begin
|
871
|
+
req.controller_class
|
872
|
+
rescue NameError
|
873
|
+
raise ActionController::RoutingError, "A route matches #{path.inspect}, but references missing controller: #{params[:controller].camelize}Controller"
|
874
|
+
end
|
630
875
|
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
if dispatcher.is_a?(Dispatcher) && dispatcher.controller(params, false)
|
637
|
-
dispatcher.prepare_params!(params)
|
638
|
-
return params
|
639
|
-
end
|
640
|
-
end
|
641
|
-
|
642
|
-
raise ActionController::RoutingError, "No route matches #{path.inspect}"
|
643
|
-
end
|
644
|
-
|
645
|
-
private
|
646
|
-
|
647
|
-
def extract_authentication(options)
|
648
|
-
if options[:user] && options[:password]
|
649
|
-
[options.delete(:user), options.delete(:password)]
|
650
|
-
else
|
651
|
-
nil
|
876
|
+
return req.path_parameters
|
877
|
+
elsif app.matches?(req) && app.engine?
|
878
|
+
path_parameters = app.rack_app.routes.recognize_path_with_request(req, path, extras, raise_on_missing: false)
|
879
|
+
return path_parameters if path_parameters
|
652
880
|
end
|
653
881
|
end
|
654
882
|
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
keys = options.delete(:_positional_keys)
|
659
|
-
keys -= options.keys if args.size < keys.size - 1 # take format into account
|
660
|
-
|
661
|
-
# Tell url_for to skip default_url_options
|
662
|
-
options.merge!(Hash[args.zip(keys).map { |v, k| [k, v] }])
|
883
|
+
if raise_on_missing
|
884
|
+
raise ActionController::RoutingError, "No route matches #{path.inspect}"
|
663
885
|
end
|
664
|
-
|
886
|
+
end
|
665
887
|
end
|
888
|
+
# :startdoc:
|
666
889
|
end
|
667
890
|
end
|