mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Caches and cache clearing seems to actually work, but the actual architecture is kind of messy. Next: CLEAN UP.
This commit is contained in:
parent
9f5cd0156a
commit
9b552fb300
5 changed files with 144 additions and 57 deletions
|
@ -19,15 +19,20 @@ module AbstractController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def clear_template_caches!
|
||||||
|
@found_layouts.clear if @found_layouts
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
def cache_layout(details)
|
def cache_layout(details)
|
||||||
layout = @found_layouts
|
layout = @found_layouts
|
||||||
values = details.values_at(:formats, :locale)
|
key = Thread.current[:format_locale_key]
|
||||||
|
|
||||||
# Cache nil
|
# Cache nil
|
||||||
if layout.key?(values)
|
if layout.key?(key)
|
||||||
return layout[values]
|
return layout[key]
|
||||||
else
|
else
|
||||||
layout[values] = yield
|
layout[key] = yield
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -111,12 +111,21 @@ module AbstractController
|
||||||
def _determine_template(options)
|
def _determine_template(options)
|
||||||
name = (options[:_template_name] || action_name).to_s
|
name = (options[:_template_name] || action_name).to_s
|
||||||
|
|
||||||
options[:_template] ||= view_paths.find(
|
options[:_template] ||= with_template_cache(name) do
|
||||||
name, { :formats => formats }, options[:_prefix], options[:_partial]
|
view_paths.find(
|
||||||
)
|
name, { :formats => formats }, options[:_prefix], options[:_partial]
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def with_template_cache(name)
|
||||||
|
yield
|
||||||
end
|
end
|
||||||
|
|
||||||
module ClassMethods
|
module ClassMethods
|
||||||
|
def clear_template_caches!
|
||||||
|
end
|
||||||
|
|
||||||
# Append a path to the list of view paths for this controller.
|
# Append a path to the list of view paths for this controller.
|
||||||
#
|
#
|
||||||
# ==== Parameters
|
# ==== Parameters
|
||||||
|
@ -134,6 +143,7 @@ module AbstractController
|
||||||
# the default view path. You may also provide a custom view path
|
# the default view path. You may also provide a custom view path
|
||||||
# (see ActionView::ViewPathSet for more information)
|
# (see ActionView::ViewPathSet for more information)
|
||||||
def prepend_view_path(path)
|
def prepend_view_path(path)
|
||||||
|
clear_template_caches!
|
||||||
self.view_paths.unshift(path)
|
self.view_paths.unshift(path)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -148,6 +158,7 @@ module AbstractController
|
||||||
# paths<ViewPathSet, Object>:: If a ViewPathSet is provided, use that;
|
# paths<ViewPathSet, Object>:: If a ViewPathSet is provided, use that;
|
||||||
# otherwise, process the parameter into a ViewPathSet.
|
# otherwise, process the parameter into a ViewPathSet.
|
||||||
def view_paths=(paths)
|
def view_paths=(paths)
|
||||||
|
clear_template_caches!
|
||||||
self._view_paths = paths.is_a?(ActionView::PathSet) ?
|
self._view_paths = paths.is_a?(ActionView::PathSet) ?
|
||||||
paths : ActionView::Base.process_view_paths(paths)
|
paths : ActionView::Base.process_view_paths(paths)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,39 @@
|
||||||
module ActionController
|
module ActionController
|
||||||
|
class HashKey
|
||||||
|
@hash_keys = Hash.new {|h,k| h[k] = Hash.new {|h,k| h[k] = {} } }
|
||||||
|
|
||||||
|
def self.get(klass, formats, locale)
|
||||||
|
@hash_keys[klass][formats][locale] ||= new(klass, formats, locale)
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_accessor :hash
|
||||||
|
def initialize(klass, formats, locale)
|
||||||
|
@hash = [formats, locale].hash
|
||||||
|
end
|
||||||
|
|
||||||
|
alias_method :eql?, :equal?
|
||||||
|
end
|
||||||
|
|
||||||
module RenderingController
|
module RenderingController
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
include AbstractController::RenderingController
|
include AbstractController::RenderingController
|
||||||
|
|
||||||
|
module ClassMethods
|
||||||
|
def clear_template_caches!
|
||||||
|
ActionView::Partials::PartialRenderer::TEMPLATES.clear
|
||||||
|
template_cache.clear
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
def template_cache
|
||||||
|
@template_cache ||= Hash.new {|h,k| h[k] = {} }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def process_action(*)
|
def process_action(*)
|
||||||
self.formats = request.formats.map {|x| x.to_sym}
|
self.formats = request.formats.map {|x| x.to_sym}
|
||||||
|
Thread.current[:format_locale_key] = HashKey.get(self.class, formats, I18n.locale)
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -34,6 +62,10 @@ module ActionController
|
||||||
controller_path
|
controller_path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def with_template_cache(name)
|
||||||
|
self.class.template_cache[Thread.current[:format_locale_key]][name] ||= super
|
||||||
|
end
|
||||||
|
|
||||||
def _determine_template(options)
|
def _determine_template(options)
|
||||||
if options.key?(:text)
|
if options.key?(:text)
|
||||||
options[:_template] = ActionView::TextTemplate.new(options[:text], formats.first)
|
options[:_template] = ActionView::TextTemplate.new(options[:text], formats.first)
|
||||||
|
|
|
@ -173,44 +173,50 @@ module ActionView
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
class PartialRenderer
|
class PartialRenderer
|
||||||
def self.partial_names
|
PARTIAL_NAMES = Hash.new {|h,k| h[k] = {} }
|
||||||
@partial_names ||= Hash.new {|h,k| h[k] = ActiveSupport::ConcurrentHash.new }
|
TEMPLATES = Hash.new {|h,k| h[k] = {} }
|
||||||
end
|
|
||||||
|
|
||||||
def self.formats
|
attr_reader :template
|
||||||
@formats ||= Hash.new {|h,k| h[k] = Hash.new{|h,k| h[k] = Hash.new {|h,k| h[k] = {}}}}
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(view_context, options, block)
|
def initialize(view_context, options, block)
|
||||||
|
@view = view_context
|
||||||
|
@partial_names = PARTIAL_NAMES[@view.controller.class]
|
||||||
|
|
||||||
|
key = Thread.current[:format_locale_key]
|
||||||
|
@templates = TEMPLATES[key] if key
|
||||||
|
|
||||||
|
setup(options, block)
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup(options, block)
|
||||||
partial = options[:partial]
|
partial = options[:partial]
|
||||||
|
|
||||||
@memo = {}
|
@options = options
|
||||||
@view = view_context
|
@locals = options[:locals] || {}
|
||||||
@options = options
|
@block = block
|
||||||
@locals = options[:locals] || {}
|
|
||||||
@block = block
|
|
||||||
|
|
||||||
# Set up some instance variables to speed up memoizing
|
if String === partial
|
||||||
@partial_names = self.class.partial_names[@view.controller.class]
|
@object = options[:object]
|
||||||
@templates = self.class.formats
|
@path = partial
|
||||||
@format = view_context.formats
|
else
|
||||||
|
@object = partial
|
||||||
# Set up the object and path
|
@path = partial_path(partial)
|
||||||
@object = partial.is_a?(String) ? options[:object] : partial
|
end
|
||||||
@path = partial_path(partial)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def render
|
def render
|
||||||
return render_collection if collection
|
if @collection = collection
|
||||||
|
render_collection
|
||||||
template = find_template
|
else
|
||||||
render_template(template, @object || @locals[template.variable_name])
|
@template = template = find_template
|
||||||
|
render_template(template, @object || @locals[template.variable_name])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_collection
|
def render_collection
|
||||||
@options[:_template] = template = find_template
|
@template = template = find_template
|
||||||
|
|
||||||
return nil if collection.blank?
|
return nil if @collection.blank?
|
||||||
|
|
||||||
if @options.key?(:spacer_template)
|
if @options.key?(:spacer_template)
|
||||||
spacer = find_template(@options[:spacer_template]).render(@view, @locals)
|
spacer = find_template(@options[:spacer_template]).render(@view, @locals)
|
||||||
|
@ -228,12 +234,14 @@ module ActionView
|
||||||
counter_name = template.counter_name
|
counter_name = template.counter_name
|
||||||
locals[counter_name] = -1
|
locals[counter_name] = -1
|
||||||
|
|
||||||
collection.each do |object|
|
@collection.each do |object|
|
||||||
locals[counter_name] += 1
|
locals[counter_name] += 1
|
||||||
locals[as] = object
|
locals[as] = object
|
||||||
|
|
||||||
segments << template.render(@view, locals)
|
segments << template.render(@view, locals)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@template = template
|
||||||
segments
|
segments
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -243,7 +251,7 @@ module ActionView
|
||||||
segments, locals, as = [], @locals, options[:as]
|
segments, locals, as = [], @locals, options[:as]
|
||||||
index, template = -1, nil
|
index, template = -1, nil
|
||||||
|
|
||||||
collection.each do |object|
|
@collection.each do |object|
|
||||||
template = find_template(partial_path(object))
|
template = find_template(partial_path(object))
|
||||||
locals[template.counter_name] = (index += 1)
|
locals[template.counter_name] = (index += 1)
|
||||||
locals[template.variable_name] = object
|
locals[template.variable_name] = object
|
||||||
|
@ -251,28 +259,28 @@ module ActionView
|
||||||
segments << template.render(@view, locals)
|
segments << template.render(@view, locals)
|
||||||
end
|
end
|
||||||
|
|
||||||
@options[:_template] = template
|
@template = template
|
||||||
segments
|
segments
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_template(template, object = @object)
|
def render_template(template, object = @object)
|
||||||
@options[:_template] ||= template
|
options, locals, view = @options, @locals, @view
|
||||||
|
locals[options[:as] || template.variable_name] = object
|
||||||
|
|
||||||
# TODO: is locals[:object] really necessary?
|
content = template.render(view, locals) do |*name|
|
||||||
@locals[:object] = @locals[template.variable_name] = object
|
|
||||||
@locals[@options[:as]] = object if @options[:as]
|
|
||||||
|
|
||||||
content = template.render(@view, @locals) do |*name|
|
|
||||||
@view._layout_for(*name, &@block)
|
@view._layout_for(*name, &@block)
|
||||||
end
|
end
|
||||||
return content if @block || !@options[:layout]
|
|
||||||
find_template(@options[:layout]).render(@view, @locals) { content }
|
|
||||||
end
|
|
||||||
|
|
||||||
|
if @block || !options[:layout]
|
||||||
|
content
|
||||||
|
else
|
||||||
|
find_template(options[:layout]).render(@view, @locals) { content }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def collection
|
def collection
|
||||||
@collection ||= if @object.respond_to?(:to_ary)
|
if @object.respond_to?(:to_ary)
|
||||||
@object
|
@object
|
||||||
elsif @options.key?(:collection)
|
elsif @options.key?(:collection)
|
||||||
@options[:collection] || []
|
@options[:collection] || []
|
||||||
|
@ -280,15 +288,19 @@ module ActionView
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_template(path = @path)
|
def find_template(path = @path)
|
||||||
return if !path
|
unless @templates
|
||||||
@templates[path][@view.controller_path][@format][I18n.locale] ||= begin
|
path && _find_template(path)
|
||||||
prefix = @view.controller.controller_path unless path.include?(?/)
|
else
|
||||||
@view.find(path, {:formats => @view.formats}, prefix, true)
|
path && @templates[path] ||= _find_template(path)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def _find_template(path)
|
||||||
|
prefix = @view.controller.controller_path unless path.include?(?/)
|
||||||
|
@view.find(path, {:formats => @view.formats}, prefix, true)
|
||||||
|
end
|
||||||
|
|
||||||
def partial_path(object = @object)
|
def partial_path(object = @object)
|
||||||
return object if object.is_a?(String)
|
|
||||||
@partial_names[object.class] ||= begin
|
@partial_names[object.class] ||= begin
|
||||||
return nil unless object.respond_to?(:to_model)
|
return nil unless object.respond_to?(:to_model)
|
||||||
|
|
||||||
|
@ -302,13 +314,25 @@ module ActionView
|
||||||
|
|
||||||
def render_partial(options)
|
def render_partial(options)
|
||||||
_evaluate_assigns_and_ivars
|
_evaluate_assigns_and_ivars
|
||||||
# TODO: Handle other details here.
|
|
||||||
self.formats = options[:_details][:formats] if options[:_details]
|
details = options[:_details]
|
||||||
_render_partial(options)
|
|
||||||
|
# Is this needed
|
||||||
|
self.formats = details[:formats] if details
|
||||||
|
renderer = PartialRenderer.new(self, options, nil)
|
||||||
|
text = renderer.render
|
||||||
|
options[:_template] = renderer.template
|
||||||
|
text
|
||||||
end
|
end
|
||||||
|
|
||||||
def _render_partial(options, &block) #:nodoc:
|
def _render_partial(options, &block) #:nodoc:
|
||||||
PartialRenderer.new(self, options, block).render
|
if @renderer
|
||||||
|
@renderer.setup(options, block)
|
||||||
|
else
|
||||||
|
@renderer = PartialRenderer.new(self, options, block)
|
||||||
|
end
|
||||||
|
|
||||||
|
@renderer.render
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -98,6 +98,21 @@ module ActionView
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
class LocalsKey
|
||||||
|
@hash_keys = Hash.new {|h,k| h[k] = Hash.new {|h,k| h[k] = {} } }
|
||||||
|
|
||||||
|
def self.get(*locals)
|
||||||
|
@hash_keys[*locals] ||= new(klass, format, locale)
|
||||||
|
end
|
||||||
|
|
||||||
|
attr_accessor :hash
|
||||||
|
def initialize(klass, format, locale)
|
||||||
|
@hash = locals.hash
|
||||||
|
end
|
||||||
|
|
||||||
|
alias_method :eql?, :equal?
|
||||||
|
end
|
||||||
|
|
||||||
def build_method_name(locals)
|
def build_method_name(locals)
|
||||||
# TODO: is locals.keys.hash reliably the same?
|
# TODO: is locals.keys.hash reliably the same?
|
||||||
@method_names[locals.keys.hash] ||=
|
@method_names[locals.keys.hash] ||=
|
||||||
|
|
Loading…
Reference in a new issue