aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_controller
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_controller')
-rw-r--r--actionpack/lib/action_controller/base.rb258
-rw-r--r--actionpack/lib/action_controller/layout.rb144
-rw-r--r--actionpack/lib/action_controller/mime_responds.rb9
-rw-r--r--actionpack/lib/action_controller/mime_type.rb14
-rwxr-xr-xactionpack/lib/action_controller/request.rb35
-rw-r--r--actionpack/lib/action_controller/rescue.rb10
-rw-r--r--actionpack/lib/action_controller/templates/rescues/diagnostics.erb5
7 files changed, 244 insertions, 231 deletions
diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb
index 50b965ce4c..78c8bf0647 100644
--- a/actionpack/lib/action_controller/base.rb
+++ b/actionpack/lib/action_controller/base.rb
@@ -514,8 +514,8 @@ module ActionController #:nodoc:
def process(request, response, method = :perform_action, *arguments) #:nodoc:
response.request = request
- initialize_template_class(response)
assign_shortcuts(request, response)
+ initialize_template_class(response)
initialize_current_url
assign_names
@@ -863,90 +863,82 @@ module ActionController #:nodoc:
def render(options = nil, extra_options = {}, &block) #:doc:
raise DoubleRenderError, "Can only render or redirect once per action" if performed?
- validate_render_arguments(options, extra_options, block_given?)
-
- if options.nil?
- options = { :template => default_template, :layout => true }
- elsif options == :update
- options = extra_options.merge({ :update => true })
- elsif options.is_a?(String) || options.is_a?(Symbol)
- case options.to_s.index('/')
- when 0
- extra_options[:file] = options
- when nil
- extra_options[:action] = options
- else
- extra_options[:template] = options
- end
+ options = { :layout => true } if options.nil?
+ original, options = options, extra_options unless options.is_a?(Hash)
+
+ layout_name = options.delete(:layout)
- options = extra_options
- end
+ _process_options(options)
+
+ if block_given?
+ @template.send(:_evaluate_assigns_and_ivars)
- layout = pick_layout(options)
- response.layout = layout.path_without_format_and_extension if layout
- logger.info("Rendering template within #{layout.path_without_format_and_extension}") if logger && layout
-
- if content_type = options[:content_type]
- response.content_type = content_type.to_s
+ generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(@template, &block)
+ response.content_type = Mime::JS
+ return render_for_text(generator.to_s)
end
-
- if location = options[:location]
- response.headers["Location"] = url_for(location)
+
+ if original
+ return render_for_name(original, layout_name, options) unless block_given?
+ end
+
+ if options.key?(:text)
+ return render_for_text(@template._render_text(options[:text],
+ _pick_layout(layout_name), options))
end
- if options.has_key?(:text)
- text = layout ? @template.render(options.merge(:text => options[:text], :layout => layout)) : options[:text]
- render_for_text(text, options[:status])
+ file, template = options.values_at(:file, :template)
+ if file || template
+ file = template.sub(/^\//, '') if template
+ return render_for_file(file, [layout_name, !!template], options)
+ end
+
+ if action_option = options[:action]
+ return render_for_action(action_option, [layout_name, true], options)
+ end
+
+ if inline = options[:inline]
+ render_for_text(@template._render_inline(inline, _pick_layout(layout_name), options))
+
+ elsif xml = options[:xml]
+ response.content_type ||= Mime::XML
+ render_for_text(xml.respond_to?(:to_xml) ? xml.to_xml : xml)
+
+ elsif js = options[:js]
+ response.content_type ||= Mime::JS
+ render_for_text(js)
+
+ elsif json = options[:json]
+ json = json.to_json unless json.is_a?(String)
+ json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
+ response.content_type ||= Mime::JSON
+ render_for_text(json)
+
+ elsif partial = options[:partial]
+ if partial == true
+ parts = [action_name_base, formats, controller_name, true]
+ elsif partial.is_a?(String)
+ parts = partial_parts(partial, options)
+ else
+ return render_for_text(@template._render_partial(options))
+ end
+
+ render_for_parts(parts, layout_name, options)
+
+ elsif options[:nothing]
+ render_for_text(nil)
else
- if file = options[:file]
- render_for_file(file, options[:status], layout, options[:locals] || {})
-
- elsif template = options[:template]
- render_for_file(template, options[:status], layout, options[:locals] || {})
-
- elsif inline = options[:inline]
- render_for_text(@template.render(options.merge(:layout => layout)), options[:status])
-
- elsif action_name = options[:action]
- render_for_file(default_template(action_name.to_s), options[:status], layout)
-
- elsif xml = options[:xml]
- response.content_type ||= Mime::XML
- render_for_text(xml.respond_to?(:to_xml) ? xml.to_xml : xml, options[:status])
-
- elsif js = options[:js]
- response.content_type ||= Mime::JS
- render_for_text(js, options[:status])
-
- elsif json = options[:json]
- json = json.to_json unless json.is_a?(String)
- json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
- response.content_type ||= Mime::JSON
- render_for_text(json, options[:status])
-
- elsif options[:partial]
- options[:partial] = default_template_name if options[:partial] == true
- if layout
- render_for_text(@template.render(:text => @template.render(options), :layout => layout), options[:status])
- else
- render_for_text(@template.render(options), options[:status])
- end
-
- elsif options[:update]
- @template.send(:_evaluate_assigns_and_ivars)
-
- generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(@template, &block)
- response.content_type = Mime::JS
- render_for_text(generator.to_s, options[:status])
+ render_for_parts([action_name, formats, controller_path], layout_name, options)
+ end
+ end
- elsif options[:nothing]
- render_for_text(nil, options[:status])
+ def formats
+ @_request.formats.map {|f| f.symbol }.compact
+ end
- else
- render_for_file(default_template, options[:status], layout)
- end
- end
+ def action_name_base(name = action_name)
+ (name.is_a?(String) ? name.sub(/^#{controller_path}\//, '') : name).to_s
end
# Renders according to the same rules as <tt>render</tt>, but returns the result in a string instead
@@ -1174,16 +1166,70 @@ module ActionController #:nodoc:
end
private
- def render_for_file(template_path, status = nil, layout = nil, locals = {}) #:nodoc:
- path = template_path.respond_to?(:path_without_format_and_extension) ? template_path.path_without_format_and_extension : template_path
- logger.info("Rendering #{path}" + (status ? " (#{status})" : '')) if logger
- render_for_text @template.render(:file => template_path, :locals => locals, :layout => layout), status
+ def _process_options(options)
+ if content_type = options[:content_type]
+ response.content_type = content_type.to_s
+ end
+
+ if location = options[:location]
+ response.headers["Location"] = url_for(location)
+ end
+
+ response.status = interpret_status(options[:status] || DEFAULT_RENDER_STATUS_CODE)
end
- def render_for_text(text = nil, status = nil, append_response = false) #:nodoc:
- @performed_render = true
+ def render_for_name(name, layout, options)
+ case name.to_s.index('/')
+ when 0
+ render_for_file(name, layout, options)
+ when nil
+ render_for_action(name, layout, options)
+ else
+ render_for_file(name.sub(/^\//, ''), [layout, true], options)
+ end
+ end
+
+ def render_for_parts(parts, layout, options = {})
+ tmp = view_paths.find_by_parts(*parts)
+ layout = _pick_layout(*layout) unless tmp.exempt_from_layout?
+
+ render_for_text(
+ @template._render_template_with_layout(tmp, layout, options, parts[3]))
+ end
+
+ def partial_parts(name, options)
+ segments = name.split("/")
+ parts = segments.pop.split(".")
+
+ case parts.size
+ when 1
+ parts
+ when 2, 3
+ extension = parts.delete_at(1).to_sym
+ if formats.include?(extension)
+ self.formats.replace [extension]
+ end
+ parts.pop if parts.size == 2
+ end
- response.status = interpret_status(status || DEFAULT_RENDER_STATUS_CODE)
+ path = parts.join(".")
+ prefix = segments[0..-1].join("/")
+ prefix = prefix.blank? ? controller_path : prefix
+ parts = [path, formats, prefix]
+ parts.push options[:object] || true
+ end
+
+ def render_for_file(file, layout, options)
+ render_for_parts([file, [request.format.to_sym]], layout, options)
+ end
+
+ def render_for_action(name, layout, options)
+ parts = [action_name_base(name), formats, controller_name]
+ render_for_parts(parts, layout, options)
+ end
+
+ def render_for_text(text = nil, append_response = false) #:nodoc:
+ @performed_render = true
if append_response
response.body ||= ''
@@ -1197,18 +1243,8 @@ module ActionController #:nodoc:
end
end
- def validate_render_arguments(options, extra_options, has_block)
- if options && (has_block && options != :update) && !options.is_a?(String) && !options.is_a?(Hash) && !options.is_a?(Symbol)
- raise RenderError, "You called render with invalid options : #{options.inspect}"
- end
-
- if !extra_options.is_a?(Hash)
- raise RenderError, "You called render with invalid options : #{options.inspect}, #{extra_options.inspect}"
- end
- end
-
def initialize_template_class(response)
- response.template = ActionView::Base.new(self.class.view_paths, {}, self)
+ @template = response.template = ActionView::Base.new(self.class.view_paths, {}, self, formats)
response.template.helpers.send :include, self.class.master_helper_module
response.redirected_to = nil
@performed_render = @performed_redirect = false
@@ -1221,7 +1257,6 @@ module ActionController #:nodoc:
@_response.session = request.session
@_session = @_response.session
- @template = @_response.template
@_headers = @_response.headers
end
@@ -1257,23 +1292,21 @@ module ActionController #:nodoc:
end
def perform_action
- if action_methods.include?(action_name)
- send(action_name)
- default_render unless performed?
- elsif respond_to? :method_missing
- method_missing action_name
- default_render unless performed?
- else
- begin
- default_render
- rescue ActionView::MissingTemplate => e
- # Was the implicit template missing, or was it another template?
- if e.path == default_template_name
- raise UnknownAction, "No action responded to #{action_name}. Actions: #{action_methods.sort.to_sentence}", caller
- else
- raise e
- end
- end
+ if called = action_methods.include?(action_name)
+ ret = send(action_name)
+ elsif called = respond_to?(:method_missing)
+ ret = method_missing(action_name)
+ end
+
+ return (performed? ? ret : default_render) if called
+
+ begin
+ default_render
+ rescue ActionView::MissingTemplate => e
+ raise e unless e.path == action_name
+ # If the path is the same as the action_name, the action is completely missing
+ raise UnknownAction, "No action responded to #{action_name}. Actions: " +
+ "#{action_methods.sort.to_sentence}", caller
end
end
@@ -1337,6 +1370,7 @@ module ActionController #:nodoc:
path.split('/', 2).last
end
+
def template_path_includes_controller?(path)
self.controller_path.split('/')[-1] == path.split('/')[0]
end
diff --git a/actionpack/lib/action_controller/layout.rb b/actionpack/lib/action_controller/layout.rb
index 159c5c7326..926ae26f92 100644
--- a/actionpack/lib/action_controller/layout.rb
+++ b/actionpack/lib/action_controller/layout.rb
@@ -2,11 +2,7 @@ module ActionController #:nodoc:
module Layout #:nodoc:
def self.included(base)
base.extend(ClassMethods)
- base.class_eval do
- class << self
- alias_method_chain :inherited, :layout
- end
- end
+ base.class_inheritable_accessor :layout_name, :layout_conditions
end
# Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in
@@ -159,122 +155,90 @@ module ActionController #:nodoc:
#
# This will render the help action with the "help" layout instead of the controller-wide "weblog_standard" layout.
module ClassMethods
+ extend ActiveSupport::Memoizable
+
# If a layout is specified, all rendered actions will have their result rendered
# when the layout <tt>yield</tt>s. This layout can itself depend on instance variables assigned during action
# performance and have access to them as any normal template would.
def layout(template_name, conditions = {}, auto = false)
add_layout_conditions(conditions)
- write_inheritable_attribute(:layout, template_name)
- write_inheritable_attribute(:auto_layout, auto)
+ self.layout_name = template_name
end
- def layout_conditions #:nodoc:
- @layout_conditions ||= read_inheritable_attribute(:layout_conditions)
+ def memoized_default_layout(formats) #:nodoc:
+ self.layout_name || begin
+ layout = default_layout_name
+ layout.is_a?(String) ? find_layout(layout, formats) : layout
+ rescue ActionView::MissingTemplate
+ end
end
- def default_layout(format) #:nodoc:
- layout = read_inheritable_attribute(:layout)
- return layout unless read_inheritable_attribute(:auto_layout)
- find_layout(layout, format)
+ def default_layout(*args)
+ (@_memoized_default_layout ||= ::ActiveSupport::ConcurrentHash.new)[args] ||= memoized_default_layout(*args)
+ end
+
+ def memoized_find_layout(layout, formats) #:nodoc:
+ return layout if layout.nil? || layout.respond_to?(:render)
+ prefix = layout.to_s =~ /layouts\// ? nil : "layouts"
+ view_paths.find_by_parts(layout.to_s, formats, prefix)
+ end
+
+ def find_layout(*args)
+ (@_memoized_find_layout ||= ::ActiveSupport::ConcurrentHash.new)[args] ||= memoized_find_layout(*args)
end
def layout_list #:nodoc:
Array(view_paths).sum([]) { |path| Dir["#{path}/layouts/**/*"] }
end
+ memoize :layout_list
- def find_layout(layout, *formats) #:nodoc:
- return layout if layout.respond_to?(:render)
- view_paths.find_template(layout.to_s =~ /layouts\// ? layout : "layouts/#{layout}", *formats)
- rescue ActionView::MissingTemplate
- nil
+ def default_layout_name
+ layout_match = name.underscore.sub(/_controller$/, '')
+ if layout_list.grep(%r{layouts/#{layout_match}(\.[a-z][0-9a-z]*)+$}).empty?
+ superclass.default_layout_name if superclass.respond_to?(:default_layout_name)
+ else
+ layout_match
+ end
end
+ memoize :default_layout_name
private
- def inherited_with_layout(child)
- inherited_without_layout(child)
- unless child.name.blank?
- layout_match = child.name.underscore.sub(/_controller$/, '').sub(/^controllers\//, '')
- child.layout(layout_match, {}, true) unless child.layout_list.grep(%r{layouts/#{layout_match}(\.[a-z][0-9a-z]*)+$}).empty?
- end
- end
-
def add_layout_conditions(conditions)
- write_inheritable_hash(:layout_conditions, normalize_conditions(conditions))
- end
-
- def normalize_conditions(conditions)
- conditions.inject({}) {|hash, (key, value)| hash.merge(key => [value].flatten.map {|action| action.to_s})}
+ # :except => :foo == :except => [:foo] == :except => "foo" == :except => ["foo"]
+ conditions.each {|k, v| conditions[k] = Array(v).map {|a| a.to_s} }
+ write_inheritable_hash(:layout_conditions, conditions)
end
end
-
- # Returns the name of the active layout. If the layout was specified as a method reference (through a symbol), this method
- # is called and the return value is used. Likewise if the layout was specified as an inline method (through a proc or method
- # object). If the layout was defined without a directory, layouts is assumed. So <tt>layout "weblog/standard"</tt> will return
- # weblog/standard, but <tt>layout "standard"</tt> will return layouts/standard.
- def active_layout(passed_layout = nil)
- layout = passed_layout || self.class.default_layout(default_template_format)
-
- active_layout = case layout
- when Symbol then __send__(layout)
- when Proc then layout.call(self)
- else layout
+
+ def active_layout(name)
+ name = self.class.default_layout(formats) if name == true
+
+ layout_name = case name
+ when Symbol then __send__(name)
+ when Proc then name.call(self)
+ else name
end
- if active_layout
- if layout = self.class.find_layout(active_layout, @template.template_format)
- layout
- else
- raise ActionView::MissingTemplate.new(self.class.view_paths, active_layout)
- end
- end
+ self.class.find_layout(layout_name, formats)
end
- private
- def candidate_for_layout?(options)
- template = options[:template] || default_template(options[:action])
- if options.values_at(:text, :xml, :json, :file, :inline, :partial, :nothing, :update).compact.empty?
- begin
- !self.view_paths.find_template(template, default_template_format).exempt_from_layout?
- rescue ActionView::MissingTemplate
- true
- end
- end
- rescue ActionView::MissingTemplate
- false
- end
-
- def pick_layout(options)
- if options.has_key?(:layout)
- case layout = options.delete(:layout)
- when FalseClass
- nil
- when NilClass, TrueClass
- active_layout if action_has_layout? && candidate_for_layout?(:template => default_template_name)
- else
- active_layout(layout)
- end
- else
- active_layout if action_has_layout? && candidate_for_layout?(options)
- end
- end
+ def _pick_layout(layout_name, implicit = false)
+ return unless layout_name || implicit
+ layout_name = true if layout_name.nil?
+ active_layout(layout_name) if action_has_layout? && layout_name
+ end
+ private
def action_has_layout?
if conditions = self.class.layout_conditions
- case
- when only = conditions[:only]
- only.include?(action_name)
- when except = conditions[:except]
- !except.include?(action_name)
- else
- true
+ if only = conditions[:only]
+ return only.include?(action_name)
+ elsif except = conditions[:except]
+ return !except.include?(action_name)
end
- else
- true
end
+ true
end
- def default_template_format
- response.template.template_format
- end
end
end
diff --git a/actionpack/lib/action_controller/mime_responds.rb b/actionpack/lib/action_controller/mime_responds.rb
index b755363873..bac225ab2a 100644
--- a/actionpack/lib/action_controller/mime_responds.rb
+++ b/actionpack/lib/action_controller/mime_responds.rb
@@ -109,16 +109,13 @@ module ActionController #:nodoc:
end
class Responder #:nodoc:
+
def initialize(controller)
@controller = controller
@request = controller.request
@response = controller.response
- if ActionController::Base.use_accept_header
- @mime_type_priority = Array(Mime::Type.lookup_by_extension(@request.parameters[:format]) || @request.accepts)
- else
- @mime_type_priority = [@request.format]
- end
+ @mime_type_priority = @request.formats
@order = []
@responses = {}
@@ -130,7 +127,7 @@ module ActionController #:nodoc:
@order << mime_type
@responses[mime_type] ||= Proc.new do
- @response.template.template_format = mime_type.to_sym
+ @response.template.formats = [mime_type.to_sym]
@response.content_type = mime_type.to_s
block_given? ? block.call : @controller.send(:render, :action => @controller.action_name)
end
diff --git a/actionpack/lib/action_controller/mime_type.rb b/actionpack/lib/action_controller/mime_type.rb
index 017626ba27..3d26870f4f 100644
--- a/actionpack/lib/action_controller/mime_type.rb
+++ b/actionpack/lib/action_controller/mime_type.rb
@@ -5,6 +5,10 @@ module Mime
EXTENSION_LOOKUP = Hash.new { |h, k| h[k] = Type.new(k) unless k.blank? }
LOOKUP = Hash.new { |h, k| h[k] = Type.new(k) unless k.blank? }
+ def self.[](type)
+ Type.lookup_by_extension(type.to_s)
+ end
+
# Encapsulates the notion of a mime type. Can be used at render time, for example, with:
#
# class PostsController < ActionController::Base
@@ -27,7 +31,7 @@ module Mime
# only needs to protect against these types.
@@browser_generated_types = Set.new [:html, :url_encoded_form, :multipart_form, :text]
cattr_reader :browser_generated_types
-
+ attr_reader :symbol
@@unverifiable_types = Set.new [:text, :json, :csv, :xml, :rss, :atom, :yaml]
def self.unverifiable_types
@@ -172,6 +176,8 @@ module Mime
def ==(mime_type)
return false if mime_type.blank?
(@synonyms + [ self ]).any? do |synonym|
+ require "ruby-debug"
+ debugger if mime_type.is_a?(Array)
synonym.to_s == mime_type.to_s || synonym.to_sym == mime_type.to_sym
end
end
@@ -187,17 +193,13 @@ module Mime
# Returns true if Action Pack should check requests using this Mime Type for possible request forgery. See
# ActionController::RequestForgeryProtection.
def verify_request?
- browser_generated?
+ @@browser_generated_types.include?(to_sym)
end
def html?
@@html_types.include?(to_sym) || @string =~ /html/
end
- def browser_generated?
- @@browser_generated_types.include?(to_sym)
- end
-
private
def method_missing(method, *args)
if method.to_s =~ /(\w+)\?$/
diff --git a/actionpack/lib/action_controller/request.rb b/actionpack/lib/action_controller/request.rb
index 09dcd684e8..f8c77241b9 100755
--- a/actionpack/lib/action_controller/request.rb
+++ b/actionpack/lib/action_controller/request.rb
@@ -101,10 +101,16 @@ module ActionController
def accepts
header = @env['HTTP_ACCEPT'].to_s.strip
+ fallback = xhr? ? Mime::JS : Mime::HTML
+
if header.empty?
- [content_type, Mime::ALL].compact
+ [content_type, fallback, Mime::ALL].compact
else
- Mime::Type.parse(header)
+ ret = Mime::Type.parse(header)
+ if ret.last == Mime::ALL
+ ret.insert(-2, fallback)
+ end
+ ret
end
end
memoize :accepts
@@ -144,24 +150,33 @@ module ActionController
end
end
+ ONLY_ALL = [Mime::ALL].freeze
+
# Returns the Mime type for the \format used in the request.
#
# GET /posts/5.xml | request.format => Mime::XML
# GET /posts/5.xhtml | request.format => Mime::HTML
# GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first depending on the value of <tt>ActionController::Base.use_accept_header</tt>
- def format
+
+ def format(view_path = [])
@format ||=
if parameters[:format]
- Mime::Type.lookup_by_extension(parameters[:format])
- elsif ActionController::Base.use_accept_header
- accepts.first
- elsif xhr?
- Mime::Type.lookup_by_extension("js")
- else
- Mime::Type.lookup_by_extension("html")
+ Mime[parameters[:format]]
+ elsif Base.use_accept_header && !(accepts == ONLY_ALL)
+ accepts.first
+ elsif xhr? then Mime::JS
+ else Mime::HTML
end
end
+ def formats
+ @formats =
+ if Base.use_accept_header
+ ret = Array(Mime[parameters[:format]] || accepts)
+ else
+ [format]
+ end
+ end
# Sets the \format by string extension, which can be used to force custom formats
# that are not controlled by the extension.
diff --git a/actionpack/lib/action_controller/rescue.rb b/actionpack/lib/action_controller/rescue.rb
index 4b7d1e32fd..3beeb2da83 100644
--- a/actionpack/lib/action_controller/rescue.rb
+++ b/actionpack/lib/action_controller/rescue.rb
@@ -125,11 +125,13 @@ module ActionController #:nodoc:
@template.instance_variable_set("@exception", exception)
@template.instance_variable_set("@rescues_path", RESCUES_TEMPLATE_PATH)
@template.instance_variable_set("@contents",
- @template.render(:file => template_path_for_local_rescue(exception)))
+ @template._render_template(template_path_for_local_rescue(exception)))
response.content_type = Mime::HTML
- render_for_file(rescues_path("layout"),
- response_code_for_rescue(exception))
+ response.status = interpret_status(response_code_for_rescue(exception))
+
+ content = @template._render_template(rescues_path("layout"))
+ render_for_text(content)
end
def rescue_action_without_handler(exception)
@@ -157,7 +159,7 @@ module ActionController #:nodoc:
end
def rescues_path(template_name)
- RESCUES_TEMPLATE_PATH["rescues/#{template_name}.erb"]
+ RESCUES_TEMPLATE_PATH.find_template("rescues/#{template_name}.erb")
end
def template_path_for_local_rescue(exception)
diff --git a/actionpack/lib/action_controller/templates/rescues/diagnostics.erb b/actionpack/lib/action_controller/templates/rescues/diagnostics.erb
index 669da1b26e..95be64511d 100644
--- a/actionpack/lib/action_controller/templates/rescues/diagnostics.erb
+++ b/actionpack/lib/action_controller/templates/rescues/diagnostics.erb
@@ -6,6 +6,5 @@
</h1>
<pre><%=h @exception.clean_message %></pre>
-<%= render :file => @rescues_path["rescues/_trace.erb"] %>
-
-<%= render :file => @rescues_path["rescues/_request_and_response.erb"] %>
+<%= @template._render_template(@rescues_path.find_template("rescues/_trace.erb")) %>
+<%= @template._render_template(@rescues_path.find_template("rescues/_request_and_response.erb")) %> \ No newline at end of file