Skip to content

Commit

Permalink
Ensure details are frozen after @details_keys lookup. The implementat…
Browse files Browse the repository at this point in the history
…ion waits to freeze until the last required moment, to avoid duping hashes.
  • Loading branch information
josevalim committed Mar 27, 2010
1 parent fdebc7f commit a09e992
Show file tree
Hide file tree
Showing 5 changed files with 21 additions and 19 deletions.
2 changes: 1 addition & 1 deletion actionmailer/lib/action_mailer/base.rb
Expand Up @@ -591,7 +591,7 @@ def collect_responses_and_parts_order(headers) #:nodoc:
responses, parts_order = [], nil

if block_given?
collector = ActionMailer::Collector.new(self) { render(action_name) }
collector = ActionMailer::Collector.new(lookup_context) { render(action_name) }
yield(collector)
parts_order = collector.responses.map { |r| r[:content_type] }
responses = collector.responses
Expand Down
3 changes: 1 addition & 2 deletions actionmailer/lib/action_mailer/collector.rb
Expand Up @@ -22,8 +22,7 @@ def any(*args, &block)

def custom(mime, options={})
options.reverse_merge!(:content_type => mime.to_s)
@context.formats = [mime.to_sym]
@context.formats.freeze
@context.freeze_formats([mime.to_sym])
options[:body] = block_given? ? yield : @default_render.call
@responses << options
end
Expand Down
3 changes: 1 addition & 2 deletions actionpack/lib/action_controller/metal/mime_responds.rb
Expand Up @@ -262,8 +262,7 @@ def retrieve_response_from_mimes(mimes=nil, &block)

if format = request.negotiate_mime(collector.order)
self.content_type ||= format.to_s
self.formats = [format.to_sym]
self.formats.freeze
lookup_context.freeze_formats([format.to_sym])
collector.response_for(format)
else
head :not_acceptable
Expand Down
21 changes: 17 additions & 4 deletions actionpack/lib/action_view/lookup_context.rb
Expand Up @@ -23,9 +23,12 @@ def #{name}
def #{name}=(value)
value = Array.wrap(value.presence || _#{name}_defaults)
@details_key = nil unless value == @details[:#{name}]
# Always set the value to handle frozen arrays
@details[:#{name}] = value
if value != @details[:#{name}]
@details_key = nil
@details = @details.dup if @details.frozen?
@details[:#{name}] = value.freeze
end
end
METHOD
end
Expand All @@ -45,7 +48,7 @@ class DetailsKey #:nodoc:
@details_keys = Hash.new

def self.get(details)
@details_keys[details] ||= new
@details_keys[details.freeze] ||= new
end

def initialize
Expand All @@ -55,6 +58,7 @@ def initialize

def initialize(view_paths, details = {})
@details, @details_key = { :handlers => default_handlers }, nil
@frozen_formats = false
self.view_paths = view_paths
self.update_details(details, true)
end
Expand Down Expand Up @@ -127,6 +131,15 @@ def details_key #:nodoc:
@details_key ||= DetailsKey.get(@details)
end

# Freeze the current formats in the lookup context. By freezing them, you are guaranteeing
# that next template lookups are not going to modify the formats. The controller can also
# use this, to ensure that formats won't be further modified (as it does in respond_to blocks).
def freeze_formats(formats, unless_frozen=false) #:nodoc:
return if unless_frozen && @frozen_formats
self.formats = formats
@frozen_formats = true
end

# Overload formats= to reject [:"*/*"] values.
def formats=(value)
value = nil if value == [:"*/*"]
Expand Down
11 changes: 1 addition & 10 deletions actionpack/lib/action_view/render/rendering.rb
Expand Up @@ -21,7 +21,7 @@ def render(options = {}, locals = {}, &block)
_render_partial(options)
else
template = _determine_template(options)
_freeze_formats(template.formats)
lookup_context.freeze_formats(template.formats, true)
_render_template(template, options[:layout], options)
end
when :update
Expand Down Expand Up @@ -62,14 +62,5 @@ def _render_template(template, layout = nil, options = {}) #:nodoc:
content
end
end

# Freeze the current formats in the lookup context. By freezing them, you are guaranteeing
# that next template lookups are not going to modify the formats. The controller can also
# use this, to ensure that formats won't be further modified (as it does in respond_to blocks).
def _freeze_formats(formats) #:nodoc:
return if self.formats.frozen?
self.formats = formats
self.formats.freeze
end
end
end

0 comments on commit a09e992

Please sign in to comment.