mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #29662 from deivid-rodriguez/engine_multiple_mount_points
Allow mounting same engine under several locations
This commit is contained in:
commit
c8ce345964
5 changed files with 112 additions and 10 deletions
|
@ -652,18 +652,25 @@ module ActionDispatch
|
|||
def define_generate_prefix(app, name)
|
||||
_route = @set.named_routes.get name
|
||||
_routes = @set
|
||||
app.routes.define_mounted_helper(name)
|
||||
|
||||
script_namer = ->(options) do
|
||||
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)
|
||||
end
|
||||
|
||||
app.routes.define_mounted_helper(name, script_namer)
|
||||
|
||||
app.routes.extend Module.new {
|
||||
def optimize_routes_generation?; false; end
|
||||
|
||||
define_method :find_script_name do |options|
|
||||
if options.key? :script_name
|
||||
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)
|
||||
script_namer.call(options)
|
||||
end
|
||||
end
|
||||
}
|
||||
|
|
|
@ -449,7 +449,7 @@ module ActionDispatch
|
|||
MountedHelpers
|
||||
end
|
||||
|
||||
def define_mounted_helper(name)
|
||||
def define_mounted_helper(name, script_namer = nil)
|
||||
return if MountedHelpers.method_defined?(name)
|
||||
|
||||
routes = self
|
||||
|
@ -457,7 +457,7 @@ module ActionDispatch
|
|||
|
||||
MountedHelpers.class_eval do
|
||||
define_method "_#{name}" do
|
||||
RoutesProxy.new(routes, _routes_context, helpers)
|
||||
RoutesProxy.new(routes, _routes_context, helpers, script_namer)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -8,9 +8,10 @@ module ActionDispatch
|
|||
attr_accessor :scope, :routes
|
||||
alias :_routes :routes
|
||||
|
||||
def initialize(routes, scope, helpers)
|
||||
def initialize(routes, scope, helpers, script_namer = nil)
|
||||
@routes, @scope = routes, scope
|
||||
@helpers = helpers
|
||||
@script_namer = script_namer
|
||||
end
|
||||
|
||||
def url_options
|
||||
|
@ -29,7 +30,9 @@ module ActionDispatch
|
|||
self.class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
||||
def #{method}(*args)
|
||||
options = args.extract_options!
|
||||
args << url_options.merge((options || {}).symbolize_keys)
|
||||
options = url_options.merge((options || {}).symbolize_keys)
|
||||
options.reverse_merge!(script_name: @script_namer.call(options)) if @script_namer
|
||||
args << options
|
||||
@helpers.#{method}(*args)
|
||||
end
|
||||
RUBY
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
* Allow mounting the same engine several times in different locations.
|
||||
|
||||
Fixes #20204.
|
||||
|
||||
*David Rodríguez*
|
||||
|
||||
* Clear screenshot files in `tmp:clear` task.
|
||||
|
||||
*Yuji Yaginuma*
|
||||
|
|
|
@ -1341,6 +1341,92 @@ YAML
|
|||
assert_equal "/foo/bukkits/bukkit", last_response.body
|
||||
end
|
||||
|
||||
test "isolated engine can be mounted under multiple static locations" do
|
||||
app_file "app/controllers/foos_controller.rb", <<-RUBY
|
||||
class FoosController < ApplicationController
|
||||
def through_fruits
|
||||
render plain: fruit_bukkits.posts_path
|
||||
end
|
||||
|
||||
def through_vegetables
|
||||
render plain: vegetable_bukkits.posts_path
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
|
||||
app_file "config/routes.rb", <<-RUBY
|
||||
Rails.application.routes.draw do
|
||||
scope "/fruits" do
|
||||
mount Bukkits::Engine => "/bukkits", as: :fruit_bukkits
|
||||
end
|
||||
|
||||
scope "/vegetables" do
|
||||
mount Bukkits::Engine => "/bukkits", as: :vegetable_bukkits
|
||||
end
|
||||
|
||||
get "/through_fruits" => "foos#through_fruits"
|
||||
get "/through_vegetables" => "foos#through_vegetables"
|
||||
end
|
||||
RUBY
|
||||
|
||||
@plugin.write "config/routes.rb", <<-RUBY
|
||||
Bukkits::Engine.routes.draw do
|
||||
resources :posts, only: :index
|
||||
end
|
||||
RUBY
|
||||
|
||||
boot_rails
|
||||
|
||||
get("/through_fruits")
|
||||
assert_equal "/fruits/bukkits/posts", last_response.body
|
||||
|
||||
get("/through_vegetables")
|
||||
assert_equal "/vegetables/bukkits/posts", last_response.body
|
||||
end
|
||||
|
||||
test "isolated engine can be mounted under multiple dynamic locations" do
|
||||
app_file "app/controllers/foos_controller.rb", <<-RUBY
|
||||
class FoosController < ApplicationController
|
||||
def through_fruits
|
||||
render plain: fruit_bukkits.posts_path(fruit_id: 1)
|
||||
end
|
||||
|
||||
def through_vegetables
|
||||
render plain: vegetable_bukkits.posts_path(vegetable_id: 1)
|
||||
end
|
||||
end
|
||||
RUBY
|
||||
|
||||
app_file "config/routes.rb", <<-RUBY
|
||||
Rails.application.routes.draw do
|
||||
resources :fruits do
|
||||
mount Bukkits::Engine => "/bukkits"
|
||||
end
|
||||
|
||||
resources :vegetables do
|
||||
mount Bukkits::Engine => "/bukkits"
|
||||
end
|
||||
|
||||
get "/through_fruits" => "foos#through_fruits"
|
||||
get "/through_vegetables" => "foos#through_vegetables"
|
||||
end
|
||||
RUBY
|
||||
|
||||
@plugin.write "config/routes.rb", <<-RUBY
|
||||
Bukkits::Engine.routes.draw do
|
||||
resources :posts, only: :index
|
||||
end
|
||||
RUBY
|
||||
|
||||
boot_rails
|
||||
|
||||
get("/through_fruits")
|
||||
assert_equal "/fruits/1/bukkits/posts", last_response.body
|
||||
|
||||
get("/through_vegetables")
|
||||
assert_equal "/vegetables/1/bukkits/posts", last_response.body
|
||||
end
|
||||
|
||||
private
|
||||
def app
|
||||
Rails.application
|
||||
|
|
Loading…
Reference in a new issue