1
0
Fork 0
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:
Rafael França 2017-07-05 15:38:39 -04:00 committed by GitHub
commit c8ce345964
5 changed files with 112 additions and 10 deletions

View file

@ -652,18 +652,25 @@ module ActionDispatch
def define_generate_prefix(app, name) def define_generate_prefix(app, name)
_route = @set.named_routes.get name _route = @set.named_routes.get name
_routes = @set _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 { app.routes.extend Module.new {
def optimize_routes_generation?; false; end def optimize_routes_generation?; false; end
define_method :find_script_name do |options| define_method :find_script_name do |options|
if options.key? :script_name if options.key? :script_name
super(options) super(options)
else else
prefix_options = options.slice(*_route.segment_keys) script_namer.call(options)
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 end
end end
} }

View file

@ -449,7 +449,7 @@ module ActionDispatch
MountedHelpers MountedHelpers
end end
def define_mounted_helper(name) def define_mounted_helper(name, script_namer = nil)
return if MountedHelpers.method_defined?(name) return if MountedHelpers.method_defined?(name)
routes = self routes = self
@ -457,7 +457,7 @@ module ActionDispatch
MountedHelpers.class_eval do MountedHelpers.class_eval do
define_method "_#{name}" do define_method "_#{name}" do
RoutesProxy.new(routes, _routes_context, helpers) RoutesProxy.new(routes, _routes_context, helpers, script_namer)
end end
end end

View file

@ -8,9 +8,10 @@ module ActionDispatch
attr_accessor :scope, :routes attr_accessor :scope, :routes
alias :_routes :routes alias :_routes :routes
def initialize(routes, scope, helpers) def initialize(routes, scope, helpers, script_namer = nil)
@routes, @scope = routes, scope @routes, @scope = routes, scope
@helpers = helpers @helpers = helpers
@script_namer = script_namer
end end
def url_options def url_options
@ -29,7 +30,9 @@ module ActionDispatch
self.class.class_eval <<-RUBY, __FILE__, __LINE__ + 1 self.class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{method}(*args) def #{method}(*args)
options = args.extract_options! 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) @helpers.#{method}(*args)
end end
RUBY RUBY

View file

@ -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. * Clear screenshot files in `tmp:clear` task.
*Yuji Yaginuma* *Yuji Yaginuma*

View file

@ -1341,6 +1341,92 @@ YAML
assert_equal "/foo/bukkits/bukkit", last_response.body assert_equal "/foo/bukkits/bukkit", last_response.body
end 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 private
def app def app
Rails.application Rails.application