Allow helpers to be deferred until the routes have been finalized

ActiveStorage::BaseController subclasses ActionController::Base.
ActionController::Base has an "inherited" hook set that includes the
routing helpers to any subclass of AC::Base.  Since
ActiveStorage::BaseController is a subclass of AC::Base, it will get
routing helpers included automatically.  Unfortunately, when the
framework is eagerly loaded, ActiveStorage::BaseController is loaded
*before* the applications routes are loaded which means it attempts to
include an "in flight" module so it gets an exception.

This commit allows a class that's interested in being extended with
routing helpers register itself such that when the routes are finalized,
it will get the helpers included.  If the routes are already finalized,
then the helpers get included immediately.
This commit is contained in:
Aaron Patterson 2018-09-25 14:58:39 -07:00
parent 8dc784292b
commit 338c3c45fa
No known key found for this signature in database
GPG Key ID: 953170BCB4FFAFC6
2 changed files with 24 additions and 5 deletions

View File

@ -7,11 +7,8 @@ module AbstractController
Module.new do
define_method(:inherited) do |klass|
super(klass)
if namespace = klass.parents.detect { |m| m.respond_to?(:railtie_routes_url_helpers) }
klass.include(namespace.railtie_routes_url_helpers(include_path_helpers))
else
klass.include(routes.url_helpers(include_path_helpers))
end
routes.include_helpers klass, include_path_helpers
end
end
end

View File

@ -379,6 +379,7 @@ module ActionDispatch
@finalized = false
@env_key = "ROUTES_#{object_id}_SCRIPT_NAME".freeze
@url_helpers = nil
@deferred_classes = []
@set = Journey::Routes.new
@router = Journey::Router.new @set
@ -434,11 +435,32 @@ module ActionDispatch
end
private :eval_block
def include_helpers(klass, include_path_helpers)
if @finalized
include_helpers_now klass, include_path_helpers
else
@deferred_classes << [klass, include_path_helpers]
end
end
def include_helpers_now(klass, include_path_helpers)
if namespace = klass.parents.detect { |m| m.respond_to?(:railtie_routes_url_helpers) }
klass.include(namespace.railtie_routes_url_helpers(include_path_helpers))
else
klass.include(url_helpers(include_path_helpers))
end
end
private :include_helpers_now
def finalize!
return if @finalized
@append.each { |blk| eval_block(blk) }
@finalized = true
@url_helpers = build_url_helper_module true
@deferred_classes.each { |klass, include_path_helpers|
include_helpers klass, include_path_helpers
}
@deferred_classes.clear
end
def clear!