mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Fix handling SCRIPT_NAME from within mounted engine's
When you mount your application at a path, for example /myapp, server should set SCRIPT_NAME to /myapp. With such information, rails application knows that it's mounted at /myapp path and it should generate routes relative to that path. Before this patch, rails handled SCRIPT_NAME correctly only for regular apps, but it failed to do it for mounted engines. The solution was to hardcode default_url_options[:script_name], which is not the best answer - it will work only when application is mounted at a fixed path. This patch fixes the situation by respecting original value of SCRIPT_NAME when generating application's routes from engine and the other way round - when you generate engine's routes from application. This is done by using one of 2 pieces of information in env - current SCRIPT_NAME or SCRIPT_NAME for a corresponding router. This is because we have 2 cases to handle: - generating engine's route from application: in this situation SCRIPT_NAME is basically SCRIPT_NAME set by the server and it indicates the place where application is mounted, so we can just pass it as :original_script_name in url_options. :original_script_name is used because if we use :script_name, router will ignore generating prefix for engine - generating application's route from engine: in this situation we already lost information about the SCRIPT_NAME that server used. For example if application is mounted at /myapp and engine is mounted at /blog, at this point SCRIPT_NAME is equal /myapp/blog. Because of that we need to keep reference to /myapp SCRIPT_NAME by binding it to the current router. Later on we can extract it and use when generating url Please note that starting from now you *should not* use default_url_options[:script_name] explicitly if your server already passes correct SCRIPT_NAME to rack env. (closes #6933)
This commit is contained in:
parent
f2557112a5
commit
5b3bb61f3f
7 changed files with 78 additions and 41 deletions
|
@ -30,9 +30,15 @@ module ActionController
|
|||
:_recall => request.symbolized_path_parameters
|
||||
).freeze
|
||||
|
||||
if _routes.equal?(env["action_dispatch.routes"])
|
||||
if (same_origin = _routes.equal?(env["action_dispatch.routes"])) ||
|
||||
(script_name = env["ROUTES_#{_routes.object_id}_SCRIPT_NAME"]) ||
|
||||
(original_script_name = env['SCRIPT_NAME'])
|
||||
@_url_options.dup.tap do |options|
|
||||
options[:script_name] = request.script_name.dup
|
||||
if original_script_name
|
||||
options[:original_script_name] = original_script_name
|
||||
else
|
||||
options[:script_name] = same_origin ? request.script_name.dup : script_name
|
||||
end
|
||||
options.freeze
|
||||
end
|
||||
else
|
||||
|
|
|
@ -163,9 +163,9 @@ module ActionDispatch
|
|||
private
|
||||
|
||||
def define_named_route_methods(name, route)
|
||||
define_url_helper route, :"#{name}_path",
|
||||
define_url_helper route, :"#{name}_path",
|
||||
route.defaults.merge(:use_route => name, :only_path => true)
|
||||
define_url_helper route, :"#{name}_url",
|
||||
define_url_helper route, :"#{name}_url",
|
||||
route.defaults.merge(:use_route => name, :only_path => false)
|
||||
end
|
||||
|
||||
|
@ -465,7 +465,7 @@ module ActionDispatch
|
|||
def use_recall_for(key)
|
||||
if @recall[key] && (!@options.key?(key) || @options[key] == @recall[key])
|
||||
if !named_route_exists? || segment_keys.include?(key)
|
||||
@options[key] = @recall.delete(key)
|
||||
@options[key] = @recall.delete(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -574,7 +574,8 @@ module ActionDispatch
|
|||
end
|
||||
|
||||
RESERVED_OPTIONS = [:host, :protocol, :port, :subdomain, :domain, :tld_length,
|
||||
:trailing_slash, :anchor, :params, :only_path, :script_name]
|
||||
:trailing_slash, :anchor, :params, :only_path, :script_name,
|
||||
:original_script_name]
|
||||
|
||||
def mounted?
|
||||
false
|
||||
|
@ -594,7 +595,13 @@ module ActionDispatch
|
|||
|
||||
user, password = extract_authentication(options)
|
||||
recall = options.delete(:_recall)
|
||||
script_name = options.delete(:script_name).presence || _generate_prefix(options)
|
||||
|
||||
original_script_name = options.delete(:original_script_name).presence
|
||||
script_name = options.delete(:script_name).presence || _generate_prefix(options)
|
||||
|
||||
if script_name && original_script_name
|
||||
script_name = original_script_name + script_name
|
||||
end
|
||||
|
||||
path_options = options.except(*RESERVED_OPTIONS)
|
||||
path_options = yield(path_options) if block_given?
|
||||
|
|
|
@ -166,18 +166,6 @@ module TestGenerationPrefix
|
|||
assert_equal "/generate", last_response.body
|
||||
end
|
||||
|
||||
test "[ENGINE] generating application's url includes default_url_options[:script_name]" do
|
||||
RailsApplication.routes.default_url_options = {:script_name => "/something"}
|
||||
get "/pure-awesomeness/blog/url_to_application"
|
||||
assert_equal "/something/generate", last_response.body
|
||||
end
|
||||
|
||||
test "[ENGINE] generating application's url should give higher priority to default_url_options[:script_name]" do
|
||||
RailsApplication.routes.default_url_options = {:script_name => "/something"}
|
||||
get "/pure-awesomeness/blog/url_to_application", {}, 'SCRIPT_NAME' => '/foo'
|
||||
assert_equal "/something/generate", last_response.body
|
||||
end
|
||||
|
||||
test "[ENGINE] generating engine's url with polymorphic path" do
|
||||
get "/pure-awesomeness/blog/polymorphic_path_for_engine"
|
||||
assert_equal "/pure-awesomeness/blog/posts/1", last_response.body
|
||||
|
@ -200,12 +188,6 @@ module TestGenerationPrefix
|
|||
assert_equal "/something/awesome/blog/posts/1", last_response.body
|
||||
end
|
||||
|
||||
test "[APP] generating engine's route should give higher priority to default_url_options[:script_name]" do
|
||||
RailsApplication.routes.default_url_options = {:script_name => "/something"}
|
||||
get "/generate", {}, 'SCRIPT_NAME' => "/foo"
|
||||
assert_equal "/something/awesome/blog/posts/1", last_response.body
|
||||
end
|
||||
|
||||
test "[APP] generating engine's url with polymorphic path" do
|
||||
get "/polymorphic_path_for_engine"
|
||||
assert_equal "/awesome/blog/posts/1", last_response.body
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
## Rails 4.0.0 (unreleased) ##
|
||||
|
||||
* Correctly handle SCRIPT_NAME when generating routes to engine in application
|
||||
that's mounted at a sub-uri. With this behavior, you *should not* use
|
||||
default_url_options[:script_name] to set proper application's mount point by
|
||||
yourself. *Piotr Sarnacki*
|
||||
|
||||
* The migration generator will now produce AddXXXToYYY/RemoveXXXFromYYY migrations with references statements, for instance
|
||||
|
||||
rails g migration AddReferencesToProducts user:references supplier:references{polymorphic}
|
||||
|
|
|
@ -494,7 +494,11 @@ module Rails
|
|||
|
||||
# Define the Rack API for this engine.
|
||||
def call(env)
|
||||
app.call(env.merge!(env_config))
|
||||
env.merge!(env_config)
|
||||
if env['SCRIPT_NAME']
|
||||
env.merge! "ROUTES_#{routes.object_id}_SCRIPT_NAME" => env['SCRIPT_NAME'].dup
|
||||
end
|
||||
app.call(env)
|
||||
end
|
||||
|
||||
# Defines additional Rack env configuration that is added on each call.
|
||||
|
|
|
@ -1193,6 +1193,54 @@ YAML
|
|||
last_response.body.split("\n").map(&:strip)
|
||||
end
|
||||
|
||||
test "paths are properly generated when application is mounted at sub-path" do
|
||||
@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
|
||||
AppTemplate::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
|
||||
|
|
|
@ -163,24 +163,14 @@ module ApplicationTests
|
|||
end
|
||||
end
|
||||
|
||||
def reset_script_name!
|
||||
Rails.application.routes.default_url_options = {}
|
||||
end
|
||||
|
||||
def script_name(script_name)
|
||||
Rails.application.routes.default_url_options = {:script_name => script_name}
|
||||
end
|
||||
|
||||
test "routes generation in engine and application" do
|
||||
# test generating engine's route from engine
|
||||
get "/john/blog/posts"
|
||||
assert_equal "/john/blog/posts/1", last_response.body
|
||||
|
||||
# test generating engine's route from engine with default_url_options
|
||||
script_name "/foo"
|
||||
get "/john/blog/posts", {}, 'SCRIPT_NAME' => "/foo"
|
||||
assert_equal "/foo/john/blog/posts/1", last_response.body
|
||||
reset_script_name!
|
||||
|
||||
# test generating engine's route from application
|
||||
get "/engine_route"
|
||||
|
@ -193,14 +183,11 @@ module ApplicationTests
|
|||
assert_equal "/john/blog/posts", last_response.body
|
||||
|
||||
# test generating engine's route from application with default_url_options
|
||||
script_name "/foo"
|
||||
get "/engine_route", {}, 'SCRIPT_NAME' => "/foo"
|
||||
assert_equal "/foo/anonymous/blog/posts", last_response.body
|
||||
|
||||
script_name "/foo"
|
||||
get "/url_for_engine_route", {}, 'SCRIPT_NAME' => "/foo"
|
||||
assert_equal "/foo/john/blog/posts", last_response.body
|
||||
reset_script_name!
|
||||
|
||||
# test generating application's route from engine
|
||||
get "/someone/blog/generate_application_route"
|
||||
|
@ -210,10 +197,8 @@ module ApplicationTests
|
|||
assert_equal "/", last_response.body
|
||||
|
||||
# test generating application's route from engine with default_url_options
|
||||
script_name "/foo"
|
||||
get "/someone/blog/generate_application_route", {}, 'SCRIPT_NAME' => '/foo'
|
||||
assert_equal "/foo/", last_response.body
|
||||
reset_script_name!
|
||||
|
||||
# test polymorphic routes
|
||||
get "/polymorphic_route"
|
||||
|
|
Loading…
Reference in a new issue