diff --git a/actionpack/lib/action_dispatch/journey/path/pattern.rb b/actionpack/lib/action_dispatch/journey/path/pattern.rb index a968df5f19..dee2980eb1 100644 --- a/actionpack/lib/action_dispatch/journey/path/pattern.rb +++ b/actionpack/lib/action_dispatch/journey/path/pattern.rb @@ -119,7 +119,8 @@ module ActionDispatch class UnanchoredRegexp < AnchoredRegexp # :nodoc: def accept(node) - %r{\A#{visit node}(?:\b|\Z)} + path = visit node + path == "/" ? %r{\A/} : %r{\A#{path}(?:\b|\Z|/)} end end diff --git a/actionpack/test/dispatch/mount_test.rb b/actionpack/test/dispatch/mount_test.rb index e42ea89f6f..758cee9930 100644 --- a/actionpack/test/dispatch/mount_test.rb +++ b/actionpack/test/dispatch/mount_test.rb @@ -27,6 +27,7 @@ class TestRoutingMount < ActionDispatch::IntegrationTest } mount SprocketsApp, at: "/sprockets" + mount SprocketsApp, at: "/star*" mount SprocketsApp => "/shorthand" mount SinatraLikeApp, at: "/fakeengine", as: :fake @@ -58,6 +59,14 @@ class TestRoutingMount < ActionDispatch::IntegrationTest def test_mounting_at_root_path get "/omg" assert_equal " -- /omg", response.body + + get "/~omg" + assert_equal " -- /~omg", response.body + end + + def test_mounting_at_path_with_non_word_character + get "/star*/omg" + assert_equal "/star* -- /omg", response.body end def test_mounting_sets_script_name diff --git a/actionpack/test/journey/path/pattern_test.rb b/actionpack/test/journey/path/pattern_test.rb index 2f39abcb92..77c19369b0 100644 --- a/actionpack/test/journey/path/pattern_test.rb +++ b/actionpack/test/journey/path/pattern_test.rb @@ -34,17 +34,17 @@ module ActionDispatch end { - "/:controller(/:action)" => %r{\A/(#{x})(?:/([^/.?]+))?(?:\b|\Z)}, - "/:controller/foo" => %r{\A/(#{x})/foo(?:\b|\Z)}, - "/:controller/:action" => %r{\A/(#{x})/([^/.?]+)(?:\b|\Z)}, - "/:controller" => %r{\A/(#{x})(?:\b|\Z)}, - "/:controller(/:action(/:id))" => %r{\A/(#{x})(?:/([^/.?]+)(?:/([^/.?]+))?)?(?:\b|\Z)}, - "/:controller/:action.xml" => %r{\A/(#{x})/([^/.?]+)\.xml(?:\b|\Z)}, - "/:controller.:format" => %r{\A/(#{x})\.([^/.?]+)(?:\b|\Z)}, - "/:controller(.:format)" => %r{\A/(#{x})(?:\.([^/.?]+))?(?:\b|\Z)}, - "/:controller/*foo" => %r{\A/(#{x})/(.+)(?:\b|\Z)}, - "/:controller/*foo/bar" => %r{\A/(#{x})/(.+)/bar(?:\b|\Z)}, - "/:foo|*bar" => %r{\A/(?:([^/.?]+)|(.+))(?:\b|\Z)}, + "/:controller(/:action)" => %r{\A/(#{x})(?:/([^/.?]+))?(?:\b|\Z|/)}, + "/:controller/foo" => %r{\A/(#{x})/foo(?:\b|\Z|/)}, + "/:controller/:action" => %r{\A/(#{x})/([^/.?]+)(?:\b|\Z|/)}, + "/:controller" => %r{\A/(#{x})(?:\b|\Z|/)}, + "/:controller(/:action(/:id))" => %r{\A/(#{x})(?:/([^/.?]+)(?:/([^/.?]+))?)?(?:\b|\Z|/)}, + "/:controller/:action.xml" => %r{\A/(#{x})/([^/.?]+)\.xml(?:\b|\Z|/)}, + "/:controller.:format" => %r{\A/(#{x})\.([^/.?]+)(?:\b|\Z|/)}, + "/:controller(.:format)" => %r{\A/(#{x})(?:\.([^/.?]+))?(?:\b|\Z|/)}, + "/:controller/*foo" => %r{\A/(#{x})/(.+)(?:\b|\Z|/)}, + "/:controller/*foo/bar" => %r{\A/(#{x})/(.+)/bar(?:\b|\Z|/)}, + "/:foo|*bar" => %r{\A/(?:([^/.?]+)|(.+))(?:\b|\Z|/)}, }.each do |path, expected| define_method(:"test_to_non_anchored_regexp_#{Regexp.escape(path)}") do path = Pattern.build(