diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index a0a12f1b0e5dd56108a8266d0bf8f2ed8d2179a6..a50b81b43985e0c6b2fce234f6be44d8b2b14d4f 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,3 +1,11 @@ +* Fix regression in mounted engine named routes generation for app deployed to + a subdirectory. `relative_url_root` was prepended to the path twice (e.g. + "/subdir/subdir/engine_path" instead of "/subdir/engine_path") + + Fixes #20920. Fixes #21459. + + *Matthew Erhard* + * ActionDispatch::Response#new no longer applies default headers. If you want default headers applied to the response object, then call `ActionDispatch::Response.create`. This change only impacts people who are diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index cfd50f616d3a51d4e583dbd43d9cbcb33bae7977..2f1c2afb9171d7ea28887cd7bc8511bb1ed844a8 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -665,6 +665,7 @@ def optimize_routes_generation?; false; end super(options) else prefix_options = options.slice(*_route.segment_keys) + prefix_options[:relative_url_root] = ''.freeze # we must actually delete prefix segment keys to avoid passing them to next url_for _route.segment_keys.each { |k| options.delete(k) } _routes.url_helpers.send("#{name}_path", prefix_options) diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index e4b8d5993e1b7350af85111500521c35cef89776..339e2b7c4abf3d4469208ea0533ed186a3d789b5 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -656,14 +656,18 @@ def generate(route_key, options, recall = {}) RESERVED_OPTIONS = [:host, :protocol, :port, :subdomain, :domain, :tld_length, :trailing_slash, :anchor, :params, :only_path, :script_name, - :original_script_name] + :original_script_name, :relative_url_root] def optimize_routes_generation? default_url_options.empty? end def find_script_name(options) - options.delete(:script_name) || relative_url_root || '' + options.delete(:script_name) || find_relative_url_root(options) || '' + end + + def find_relative_url_root(options) + options.delete(:relative_url_root) || relative_url_root end def path_for(options, route_name = nil) diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 79bd7a8241595f1f915544a369eedb6bddf9e028..2c82f728ee6284144afc01c7b7e95399efcfd489 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -1304,6 +1304,55 @@ def index assert_equal '/foo/bukkits/bukkit', last_response.body end + test "paths are properly generated when application is mounted at sub-path and relative_url_root is set" do + add_to_config "config.relative_url_root = '/foo'" + + @plugin.write "lib/bukkits.rb", <<-RUBY + module Bukkits + class Engine < ::Rails::Engine + isolate_namespace Bukkits + end + end + RUBY + + app_file "app/controllers/bar_controller.rb", <<-RUBY + class BarController < ApplicationController + def index + render text: bukkits.bukkit_path + end + end + RUBY + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + get '/bar' => 'bar#index', :as => 'bar' + mount Bukkits::Engine => "/bukkits", :as => "bukkits" + end + RUBY + + @plugin.write "config/routes.rb", <<-RUBY + Bukkits::Engine.routes.draw do + get '/bukkit' => 'bukkit#index' + end + RUBY + + @plugin.write "app/controllers/bukkits/bukkit_controller.rb", <<-RUBY + class Bukkits::BukkitController < ActionController::Base + def index + render text: main_app.bar_path + end + end + RUBY + + boot_rails + + get("/bukkits/bukkit", {}, {'SCRIPT_NAME' => '/foo'}) + assert_equal '/foo/bar', last_response.body + + get("/bar", {}, {'SCRIPT_NAME' => '/foo'}) + assert_equal '/foo/bukkits/bukkit', last_response.body + end + private def app Rails.application