未验证 提交 973b62dc 编写于 作者: A Aaron Patterson 提交者: GitHub

Merge pull request #35036 from rails/av-base-subclass

Move compiled ERB to an AV::Base subclass
......@@ -15,6 +15,10 @@ def initialize(assigns)
super(renderer, assigns)
end
def compiled_method_container
self.class
end
def debug_params(params)
clean_params = params.clone
clean_params.delete("action")
......
* 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/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 CompiledTemplates #: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 @@ def cache_template_loading=(value)
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 @@ def run(method, locals, buffer, &block)
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 @@ def self.get(details)
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 @@
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 @@ class Railtie < Rails::Engine # :nodoc:
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,24 +35,36 @@ def process(*) #:nodoc:
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
Class.new(ActionView::Base) do
if routes
include routes.url_helpers(supports_path)
include routes.mounted_helpers
end
if helpers
include helpers
end
def _routes
end
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
end
if helpers
include helpers
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
def view_context_class
......
......@@ -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 @@ class Template
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 @@ def #{method_name}(local_assigns, output_buffer)
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 @@ def view
@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 @@ def render_erb(string)
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 @@ def render(*args)
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)
......
......@@ -11,10 +11,13 @@ class AVLogSubscriberTest < ActiveSupport::TestCase
def setup
super
view_paths = ActionController::Base.view_paths
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 @@ class TestController < ActionController::Base
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 @@ def combined_fragment_cache_key(key)
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 CachedCustomer < Customer; end
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 @@ class TestController < ActionController::Base
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 @@ def find_template(*args)
end
class Context < ActionView::Base
def initialize
def initialize(*)
super
@output_buffer = "original"
@virtual_path = nil
end
......@@ -63,7 +64,8 @@ def render(locals = {})
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 @@ class ::DummySerializer < ActiveJob::Serializers::ObjectSerializer; end
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 @@ class ::DummySerializer < ActiveJob::Serializers::ObjectSerializer; end
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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册