mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #35036 from rails/av-base-subclass
Move compiled ERB to an AV::Base subclass
This commit is contained in:
commit
973b62dcdd
19 changed files with 135 additions and 64 deletions
|
@ -15,6 +15,10 @@ module ActionDispatch
|
|||
super(renderer, assigns)
|
||||
end
|
||||
|
||||
def compiled_method_container
|
||||
self.class
|
||||
end
|
||||
|
||||
def debug_params(params)
|
||||
clean_params = params.clone
|
||||
clean_params.delete("action")
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
* ActionView::Template.finalize_compiled_template_methods is deprecated with
|
||||
no replacement.
|
||||
|
||||
*tenderlove*
|
||||
|
||||
* config.action_view.finalize_compiled_template_methods is deprecated with
|
||||
no replacement.
|
||||
|
||||
*tenderlove*
|
||||
|
||||
* Ensure unique DOM IDs for collection inputs with float values.
|
||||
Fixes #34974
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@ module ActionView
|
|||
eager_autoload do
|
||||
autoload :Base
|
||||
autoload :Context
|
||||
autoload :CompiledTemplates, "action_view/context"
|
||||
autoload :Digestor
|
||||
autoload :Helpers
|
||||
autoload :LookupContext
|
||||
|
|
|
@ -11,10 +11,6 @@ require "action_view/template"
|
|||
require "action_view/lookup_context"
|
||||
|
||||
module ActionView #:nodoc:
|
||||
module CompiledTemplates #:nodoc:
|
||||
# holds compiled template code
|
||||
end
|
||||
|
||||
# = Action View Base
|
||||
#
|
||||
# Action View templates can be written in several ways.
|
||||
|
@ -146,8 +142,6 @@ module ActionView #:nodoc:
|
|||
class Base
|
||||
include Helpers, ::ERB::Util, Context
|
||||
|
||||
include CompiledTemplates
|
||||
|
||||
# Specify the proc used to decorate input tags that refer to attributes with errors.
|
||||
cattr_accessor :field_error_proc, default: Proc.new { |html_tag, instance| "<div class=\"field_with_errors\">#{html_tag}</div>".html_safe }
|
||||
|
||||
|
@ -186,6 +180,20 @@ module ActionView #:nodoc:
|
|||
def xss_safe? #:nodoc:
|
||||
true
|
||||
end
|
||||
|
||||
def with_empty_template_cache # :nodoc:
|
||||
subclass = Class.new(self) {
|
||||
# We can't implement these as self.class because subclasses will
|
||||
# share the same template cache as superclasses, so "changed?" won't work
|
||||
# correctly.
|
||||
define_method(:compiled_method_container) { subclass }
|
||||
define_singleton_method(:compiled_method_container) { subclass }
|
||||
}
|
||||
end
|
||||
|
||||
def changed?(other) # :nodoc:
|
||||
compiled_method_container != other.compiled_method_container
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :view_renderer
|
||||
|
@ -260,7 +268,11 @@ module ActionView #:nodoc:
|
|||
end
|
||||
|
||||
def compiled_method_container
|
||||
CompiledTemplates
|
||||
raise NotImplementedError, <<~msg
|
||||
Subclasses of ActionView::Base must implement `compiled_method_container`
|
||||
or use the class method `with_empty_template_cache` for constructing
|
||||
an ActionView::Base subclass that has an empty cache.
|
||||
msg
|
||||
end
|
||||
|
||||
ActiveSupport.run_load_hooks(:action_view, self)
|
||||
|
|
|
@ -68,12 +68,17 @@ module ActionView
|
|||
end
|
||||
|
||||
def self.clear
|
||||
@view_context_class = nil
|
||||
@details_keys.clear
|
||||
end
|
||||
|
||||
def self.digest_caches
|
||||
@details_keys.values
|
||||
end
|
||||
|
||||
def self.view_context_class(klass)
|
||||
@view_context_class ||= klass.with_empty_template_cache
|
||||
end
|
||||
end
|
||||
|
||||
# Add caching behavior on top of Details.
|
||||
|
|
|
@ -6,11 +6,13 @@ require "rails"
|
|||
module ActionView
|
||||
# = Action View Railtie
|
||||
class Railtie < Rails::Engine # :nodoc:
|
||||
NULL_OPTION = Object.new
|
||||
|
||||
config.action_view = ActiveSupport::OrderedOptions.new
|
||||
config.action_view.embed_authenticity_token_in_remote_forms = nil
|
||||
config.action_view.debug_missing_translation = true
|
||||
config.action_view.default_enforce_utf8 = nil
|
||||
config.action_view.finalize_compiled_template_methods = true
|
||||
config.action_view.finalize_compiled_template_methods = NULL_OPTION
|
||||
|
||||
config.eager_load_namespaces << ActionView
|
||||
|
||||
|
@ -48,8 +50,11 @@ module ActionView
|
|||
|
||||
initializer "action_view.finalize_compiled_template_methods" do |app|
|
||||
ActiveSupport.on_load(:action_view) do
|
||||
ActionView::Template.finalize_compiled_template_methods =
|
||||
app.config.action_view.delete(:finalize_compiled_template_methods)
|
||||
option = app.config.action_view.delete(:finalize_compiled_template_methods)
|
||||
|
||||
if option != NULL_OPTION
|
||||
ActiveSupport::Deprecation.warn "action_view.finalize_compiled_template_methods is deprecated and has no effect"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -35,13 +35,14 @@ module ActionView
|
|||
end
|
||||
|
||||
module ClassMethods
|
||||
def view_context_class
|
||||
@view_context_class ||= begin
|
||||
supports_path = supports_path?
|
||||
routes = respond_to?(:_routes) && _routes
|
||||
helpers = respond_to?(:_helpers) && _helpers
|
||||
def _routes
|
||||
end
|
||||
|
||||
Class.new(ActionView::Base) do
|
||||
def _helpers
|
||||
end
|
||||
|
||||
def build_view_context_class(klass, supports_path, routes, helpers)
|
||||
Class.new(klass) do
|
||||
if routes
|
||||
include routes.url_helpers(supports_path)
|
||||
include routes.mounted_helpers
|
||||
|
@ -52,6 +53,17 @@ module ActionView
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
def view_context_class
|
||||
klass = ActionView::LookupContext::DetailsKey.view_context_class(ActionView::Base)
|
||||
|
||||
@view_context_class ||= build_view_context_class(klass, supports_path?, _routes, _helpers)
|
||||
|
||||
if klass.changed?(@view_context_class)
|
||||
@view_context_class = build_view_context_class(klass, supports_path?, _routes, _helpers)
|
||||
end
|
||||
|
||||
@view_context_class
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
require "active_support/core_ext/object/try"
|
||||
require "active_support/core_ext/kernel/singleton_class"
|
||||
require "active_support/deprecation"
|
||||
require "thread"
|
||||
require "delegate"
|
||||
|
||||
|
@ -10,7 +11,13 @@ module ActionView
|
|||
class Template
|
||||
extend ActiveSupport::Autoload
|
||||
|
||||
mattr_accessor :finalize_compiled_template_methods, default: true
|
||||
def self.finalize_compiled_template_methods
|
||||
ActiveSupport::Deprecation.warn "ActionView::Template.finalize_compiled_template_methods is deprecated and has no effect"
|
||||
end
|
||||
|
||||
def self.finalize_compiled_template_methods=(_)
|
||||
ActiveSupport::Deprecation.warn "ActionView::Template.finalize_compiled_template_methods= is deprecated and has no effect"
|
||||
end
|
||||
|
||||
# === Encodings in ActionView::Template
|
||||
#
|
||||
|
@ -118,16 +125,6 @@ module ActionView
|
|||
|
||||
attr_reader :source, :identifier, :handler, :original_encoding, :updated_at
|
||||
|
||||
# This finalizer is needed (and exactly with a proc inside another proc)
|
||||
# otherwise templates leak in development.
|
||||
Finalizer = proc do |method_name, mod| # :nodoc:
|
||||
proc do
|
||||
mod.module_eval do
|
||||
remove_possible_method method_name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :variable
|
||||
|
||||
def initialize(source, identifier, handler, details)
|
||||
|
@ -337,9 +334,6 @@ module ActionView
|
|||
end
|
||||
|
||||
mod.module_eval(source, identifier, 0)
|
||||
if finalize_compiled_template_methods
|
||||
ObjectSpace.define_finalizer(self, Finalizer[method_name, mod])
|
||||
end
|
||||
end
|
||||
|
||||
def handle_render_error(view, e)
|
||||
|
|
|
@ -48,7 +48,8 @@ module RenderERBUtils
|
|||
@view ||= begin
|
||||
path = ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH)
|
||||
view_paths = ActionView::PathSet.new([path])
|
||||
ActionView::Base.with_view_paths(view_paths)
|
||||
view = ActionView::Base.with_empty_template_cache
|
||||
view.with_view_paths(view_paths)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -61,7 +62,8 @@ module RenderERBUtils
|
|||
ActionView::Template.handler_for_extension(:erb),
|
||||
{})
|
||||
|
||||
template.render(ActionView::Base.empty, {}).strip
|
||||
view = ActionView::Base.with_empty_template_cache
|
||||
template.render(view.empty, {}).strip
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -10,8 +10,10 @@ class MultifetchCacheTest < ActiveRecordTestCase
|
|||
|
||||
def setup
|
||||
view_paths = ActionController::Base.view_paths
|
||||
view_paths.each(&:clear_cache)
|
||||
ActionView::LookupContext.fallbacks.each(&:clear_cache)
|
||||
|
||||
@view = Class.new(ActionView::Base) do
|
||||
@view = Class.new(ActionView::Base.with_empty_template_cache) do
|
||||
def view_cache_dependencies
|
||||
[]
|
||||
end
|
||||
|
|
|
@ -3,7 +3,18 @@
|
|||
require "abstract_unit"
|
||||
|
||||
class CompiledTemplatesTest < ActiveSupport::TestCase
|
||||
teardown do
|
||||
attr_reader :view_class
|
||||
|
||||
def setup
|
||||
super
|
||||
view_paths = ActionController::Base.view_paths
|
||||
view_paths.each(&:clear_cache)
|
||||
ActionView::LookupContext.fallbacks.each(&:clear_cache)
|
||||
@view_class = ActionView::Base.with_empty_template_cache
|
||||
end
|
||||
|
||||
def teardown
|
||||
super
|
||||
ActionView::LookupContext::DetailsKey.clear
|
||||
end
|
||||
|
||||
|
@ -72,13 +83,13 @@ class CompiledTemplatesTest < ActiveSupport::TestCase
|
|||
|
||||
def render_with_cache(*args)
|
||||
view_paths = ActionController::Base.view_paths
|
||||
ActionView::Base.with_view_paths(view_paths, {}).render(*args)
|
||||
view_class.with_view_paths(view_paths, {}).render(*args)
|
||||
end
|
||||
|
||||
def render_without_cache(*args)
|
||||
path = ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH)
|
||||
view_paths = ActionView::PathSet.new([path])
|
||||
ActionView::Base.with_view_paths(view_paths, {}).render(*args)
|
||||
view_class.with_view_paths(view_paths, {}).render(*args)
|
||||
end
|
||||
|
||||
def modify_template(template, content)
|
||||
|
|
|
@ -12,9 +12,12 @@ class AVLogSubscriberTest < ActiveSupport::TestCase
|
|||
super
|
||||
|
||||
view_paths = ActionController::Base.view_paths
|
||||
view_paths.each(&:clear_cache)
|
||||
ActionView::LookupContext.fallbacks.each(&:clear_cache)
|
||||
|
||||
lookup_context = ActionView::LookupContext.new(view_paths, {}, ["test"])
|
||||
renderer = ActionView::Renderer.new(lookup_context)
|
||||
@view = ActionView::Base.new(renderer, {})
|
||||
@view = ActionView::Base.with_empty_template_cache.new(renderer, {})
|
||||
|
||||
ActionView::LogSubscriber.attach_to :action_view
|
||||
|
||||
|
|
|
@ -9,7 +9,8 @@ end
|
|||
module RenderTestCases
|
||||
def setup_view(paths)
|
||||
@assigns = { secret: "in the sauce" }
|
||||
@view = Class.new(ActionView::Base) do
|
||||
|
||||
@view = Class.new(ActionView::Base.with_empty_template_cache) do
|
||||
def view_cache_dependencies; []; end
|
||||
|
||||
def combined_fragment_cache_key(key)
|
||||
|
@ -17,7 +18,9 @@ module RenderTestCases
|
|||
end
|
||||
end.with_view_paths(paths, @assigns)
|
||||
|
||||
@controller_view = TestController.new.view_context
|
||||
controller = TestController.new
|
||||
|
||||
@controller_view = controller.view_context_class.with_empty_template_cache.new(controller.view_renderer, controller.view_assigns, controller)
|
||||
|
||||
# Reload and register danish language for testing
|
||||
I18n.backend.store_translations "da", {}
|
||||
|
@ -629,6 +632,8 @@ class CachedViewRenderTest < ActiveSupport::TestCase
|
|||
# Ensure view path cache is primed
|
||||
def setup
|
||||
view_paths = ActionController::Base.view_paths
|
||||
view_paths.each(&:clear_cache)
|
||||
ActionView::LookupContext.fallbacks.each(&:clear_cache)
|
||||
assert_equal ActionView::OptimizedFileSystemResolver, view_paths.first.class
|
||||
setup_view(view_paths)
|
||||
end
|
||||
|
@ -645,6 +650,9 @@ class LazyViewRenderTest < ActiveSupport::TestCase
|
|||
# Test the same thing as above, but make sure the view path
|
||||
# is not eager loaded
|
||||
def setup
|
||||
view_paths = ActionController::Base.view_paths
|
||||
view_paths.each(&:clear_cache)
|
||||
ActionView::LookupContext.fallbacks.each(&:clear_cache)
|
||||
path = ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH)
|
||||
view_paths = ActionView::PathSet.new([path])
|
||||
assert_equal ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH), view_paths.first
|
||||
|
@ -704,6 +712,8 @@ class CachedCollectionViewRenderTest < ActiveSupport::TestCase
|
|||
setup do
|
||||
view_paths = ActionController::Base.view_paths
|
||||
assert_equal ActionView::OptimizedFileSystemResolver, view_paths.first.class
|
||||
view_paths.each(&:clear_cache)
|
||||
ActionView::LookupContext.fallbacks.each(&:clear_cache)
|
||||
|
||||
ActionView::PartialRenderer.collection_cache = ActiveSupport::Cache::MemoryStore.new
|
||||
|
||||
|
|
|
@ -8,8 +8,11 @@ end
|
|||
class SetupFiberedBase < ActiveSupport::TestCase
|
||||
def setup
|
||||
view_paths = ActionController::Base.view_paths
|
||||
view_paths.each(&:clear_cache)
|
||||
ActionView::LookupContext.fallbacks.each(&:clear_cache)
|
||||
|
||||
@assigns = { secret: "in the sauce", name: nil }
|
||||
@view = ActionView::Base.with_view_paths(view_paths, @assigns)
|
||||
@view = ActionView::Base.with_empty_template_cache.with_view_paths(view_paths, @assigns)
|
||||
@controller_view = TestController.new.view_context
|
||||
end
|
||||
|
||||
|
|
|
@ -19,7 +19,8 @@ class TestERBTemplate < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
class Context < ActionView::Base
|
||||
def initialize
|
||||
def initialize(*)
|
||||
super
|
||||
@output_buffer = "original"
|
||||
@virtual_path = nil
|
||||
end
|
||||
|
@ -63,7 +64,8 @@ class TestERBTemplate < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
def setup
|
||||
@context = Context.new
|
||||
@context = Context.with_empty_template_cache.empty
|
||||
super
|
||||
end
|
||||
|
||||
def test_basic_template
|
||||
|
|
|
@ -36,7 +36,10 @@ class TranslationHelperTest < ActiveSupport::TestCase
|
|||
}
|
||||
}
|
||||
)
|
||||
@view = ::ActionView::Base.with_view_paths(ActionController::Base.view_paths, {})
|
||||
view_paths = ActionController::Base.view_paths
|
||||
view_paths.each(&:clear_cache)
|
||||
ActionView::LookupContext.fallbacks.each(&:clear_cache)
|
||||
@view = ::ActionView::Base.with_empty_template_cache.with_view_paths(view_paths, {})
|
||||
end
|
||||
|
||||
teardown do
|
||||
|
|
|
@ -590,13 +590,6 @@ Defaults to `'signed cookie'`.
|
|||
|
||||
* `config.action_view.default_enforce_utf8` determines whether forms are generated with a hidden tag that forces older versions of Internet Explorer to submit forms encoded in UTF-8. This defaults to `false`.
|
||||
|
||||
* `config.action_view.finalize_compiled_template_methods` determines
|
||||
whether the methods on `ActionView::CompiledTemplates` that templates
|
||||
compile themselves to are removed when template instances are
|
||||
destroyed by the garbage collector. This helps prevent memory leaks in
|
||||
development mode, but for large test suites, disabling this option in
|
||||
the test environment can improve performance. This defaults to `true`.
|
||||
|
||||
|
||||
### Configuring Action Mailbox
|
||||
|
||||
|
|
|
@ -48,7 +48,4 @@ Rails.application.configure do
|
|||
|
||||
# Raises error for missing translations.
|
||||
# config.action_view.raise_on_missing_translations = true
|
||||
|
||||
# Prevent expensive template finalization at end of test suite runs.
|
||||
config.action_view.finalize_compiled_template_methods = false
|
||||
end
|
||||
|
|
|
@ -2094,7 +2094,9 @@ module ApplicationTests
|
|||
|
||||
test "ActionView::Template.finalize_compiled_template_methods is true by default" do
|
||||
app "test"
|
||||
assert_equal true, ActionView::Template.finalize_compiled_template_methods
|
||||
assert_deprecated do
|
||||
ActionView::Template.finalize_compiled_template_methods
|
||||
end
|
||||
end
|
||||
|
||||
test "ActionView::Template.finalize_compiled_template_methods can be configured via config.action_view.finalize_compiled_template_methods" do
|
||||
|
@ -2106,7 +2108,9 @@ module ApplicationTests
|
|||
|
||||
app "test"
|
||||
|
||||
assert_equal false, ActionView::Template.finalize_compiled_template_methods
|
||||
assert_deprecated do
|
||||
ActionView::Template.finalize_compiled_template_methods
|
||||
end
|
||||
end
|
||||
|
||||
test "ActiveJob::Base.return_false_on_aborted_enqueue is true by default" do
|
||||
|
|
Loading…
Reference in a new issue