actionpack 3.0.20 → 3.1.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- data/CHANGELOG +88 -142
- data/MIT-LICENSE +1 -1
- data/README.rdoc +5 -6
- data/lib/abstract_controller.rb +1 -0
- data/lib/abstract_controller/asset_paths.rb +2 -2
- data/lib/abstract_controller/base.rb +24 -19
- data/lib/abstract_controller/callbacks.rb +19 -19
- data/lib/abstract_controller/helpers.rb +11 -13
- data/lib/abstract_controller/layouts.rb +4 -5
- data/lib/abstract_controller/railties/routes_helpers.rb +18 -0
- data/lib/abstract_controller/rendering.rb +34 -31
- data/lib/abstract_controller/url_for.rb +27 -0
- data/lib/abstract_controller/view_paths.rb +31 -6
- data/lib/action_controller.rb +5 -3
- data/lib/action_controller/base.rb +15 -16
- data/lib/action_controller/caching.rb +2 -2
- data/lib/action_controller/caching/actions.rb +11 -12
- data/lib/action_controller/caching/fragments.rb +41 -19
- data/lib/action_controller/caching/pages.rb +3 -9
- data/lib/action_controller/caching/sweeping.rb +0 -1
- data/lib/action_controller/deprecated.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +1 -1
- data/lib/action_controller/metal.rb +78 -20
- data/lib/action_controller/metal/compatibility.rb +0 -9
- data/lib/action_controller/metal/conditional_get.rb +9 -9
- data/lib/action_controller/metal/data_streaming.rb +145 -0
- data/lib/action_controller/metal/force_ssl.rb +35 -0
- data/lib/action_controller/metal/head.rb +1 -1
- data/lib/action_controller/metal/helpers.rb +37 -44
- data/lib/action_controller/metal/hide_actions.rb +2 -3
- data/lib/action_controller/metal/http_authentication.rb +41 -38
- data/lib/action_controller/metal/implicit_render.rb +13 -13
- data/lib/action_controller/metal/instrumentation.rb +2 -2
- data/lib/action_controller/metal/mime_responds.rb +25 -19
- data/lib/action_controller/metal/params_wrapper.rb +224 -0
- data/lib/action_controller/metal/redirecting.rb +6 -2
- data/lib/action_controller/metal/renderers.rb +50 -36
- data/lib/action_controller/metal/rendering.rb +34 -25
- data/lib/action_controller/metal/request_forgery_protection.rb +18 -36
- data/lib/action_controller/metal/responder.rb +47 -12
- data/lib/action_controller/metal/streaming.rb +244 -138
- data/lib/action_controller/metal/testing.rb +0 -9
- data/lib/action_controller/metal/url_for.rb +12 -14
- data/lib/action_controller/railtie.rb +19 -37
- data/lib/action_controller/railties/paths.rb +24 -0
- data/lib/action_controller/record_identifier.rb +4 -10
- data/lib/action_controller/test_case.rb +36 -19
- data/lib/action_controller/vendor/html-scanner/html/node.rb +5 -5
- data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +3 -3
- data/lib/action_controller/vendor/html-scanner/html/selector.rb +2 -0
- data/lib/action_dispatch.rb +4 -1
- data/lib/action_dispatch/http/cache.rb +5 -32
- data/lib/action_dispatch/http/filter_parameters.rb +3 -1
- data/lib/action_dispatch/http/mime_negotiation.rb +22 -3
- data/lib/action_dispatch/http/mime_type.rb +45 -5
- data/lib/action_dispatch/http/rack_cache.rb +58 -0
- data/lib/action_dispatch/http/request.rb +27 -41
- data/lib/action_dispatch/http/response.rb +56 -54
- data/lib/action_dispatch/http/upload.rb +1 -11
- data/lib/action_dispatch/http/url.rb +102 -42
- data/lib/action_dispatch/middleware/callbacks.rb +8 -25
- data/lib/action_dispatch/middleware/closed_error.rb +7 -0
- data/lib/action_dispatch/middleware/cookies.rb +37 -15
- data/lib/action_dispatch/middleware/flash.rb +80 -11
- data/lib/action_dispatch/middleware/params_parser.rb +2 -2
- data/lib/action_dispatch/middleware/reloader.rb +76 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +56 -226
- data/lib/action_dispatch/middleware/session/cookie_store.rb +20 -44
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -46
- data/lib/action_dispatch/middleware/show_exceptions.rb +15 -2
- data/lib/action_dispatch/middleware/stack.rb +50 -17
- data/lib/action_dispatch/middleware/static.rb +41 -29
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +2 -6
- data/lib/action_dispatch/railtie.rb +8 -0
- data/lib/action_dispatch/routing.rb +13 -1
- data/lib/action_dispatch/routing/mapper.rb +345 -227
- data/lib/action_dispatch/routing/polymorphic_routes.rb +33 -13
- data/lib/action_dispatch/routing/redirection.rb +110 -0
- data/lib/action_dispatch/routing/route.rb +15 -13
- data/lib/action_dispatch/routing/route_set.rb +116 -90
- data/lib/action_dispatch/routing/routes_proxy.rb +35 -0
- data/lib/action_dispatch/routing/url_for.rb +25 -1
- data/lib/action_dispatch/testing/assertions/response.rb +8 -10
- data/lib/action_dispatch/testing/assertions/routing.rb +15 -15
- data/lib/action_dispatch/testing/assertions/selector.rb +13 -220
- data/lib/action_dispatch/testing/integration.rb +37 -28
- data/lib/action_dispatch/testing/performance_test.rb +1 -3
- data/lib/action_dispatch/testing/test_process.rb +1 -1
- data/lib/action_dispatch/testing/test_request.rb +9 -3
- data/lib/action_dispatch/testing/test_response.rb +4 -111
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/version.rb +3 -3
- data/lib/action_view.rb +39 -24
- data/lib/action_view/base.rb +61 -86
- data/lib/action_view/buffers.rb +43 -0
- data/lib/action_view/context.rb +21 -24
- data/lib/action_view/flows.rb +79 -0
- data/lib/action_view/helpers.rb +8 -6
- data/lib/action_view/helpers/active_model_helper.rb +0 -23
- data/lib/action_view/helpers/asset_paths.rb +79 -0
- data/lib/action_view/helpers/asset_tag_helper.rb +30 -500
- data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +147 -0
- data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +101 -0
- data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +200 -0
- data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +152 -0
- data/lib/action_view/helpers/atom_feed_helper.rb +2 -2
- data/lib/action_view/helpers/cache_helper.rb +11 -19
- data/lib/action_view/helpers/capture_helper.rb +19 -8
- data/lib/action_view/helpers/controller_helper.rb +21 -0
- data/lib/action_view/helpers/csrf_helper.rb +22 -4
- data/lib/action_view/helpers/date_helper.rb +36 -22
- data/lib/action_view/helpers/form_helper.rb +199 -113
- data/lib/action_view/helpers/form_options_helper.rb +10 -11
- data/lib/action_view/helpers/form_tag_helper.rb +94 -22
- data/lib/action_view/helpers/javascript_helper.rb +24 -107
- data/lib/action_view/helpers/number_helper.rb +36 -33
- data/lib/action_view/helpers/output_safety_helper.rb +38 -0
- data/lib/action_view/helpers/record_tag_helper.rb +6 -6
- data/lib/action_view/helpers/rendering_helper.rb +90 -0
- data/lib/action_view/helpers/sanitize_helper.rb +2 -2
- data/lib/action_view/helpers/sprockets_helper.rb +69 -0
- data/lib/action_view/helpers/tag_helper.rb +34 -12
- data/lib/action_view/helpers/text_helper.rb +30 -145
- data/lib/action_view/helpers/translation_helper.rb +10 -17
- data/lib/action_view/helpers/url_helper.rb +70 -67
- data/lib/action_view/locale/en.yml +1 -1
- data/lib/action_view/lookup_context.rb +36 -14
- data/lib/action_view/{paths.rb → path_set.rb} +9 -8
- data/lib/action_view/railtie.rb +12 -4
- data/lib/action_view/renderer/abstract_renderer.rb +36 -0
- data/lib/action_view/{render/partials.rb → renderer/partial_renderer.rb} +147 -146
- data/lib/action_view/renderer/renderer.rb +54 -0
- data/lib/action_view/renderer/streaming_template_renderer.rb +106 -0
- data/lib/action_view/renderer/template_renderer.rb +74 -0
- data/lib/action_view/template.rb +91 -54
- data/lib/action_view/template/error.rb +11 -8
- data/lib/action_view/template/handler.rb +9 -1
- data/lib/action_view/template/handlers.rb +9 -9
- data/lib/action_view/template/handlers/builder.rb +4 -4
- data/lib/action_view/template/handlers/erb.rb +21 -41
- data/lib/action_view/template/resolver.rb +171 -57
- data/lib/action_view/template/text.rb +0 -4
- data/lib/action_view/test_case.rb +32 -16
- data/lib/action_view/testing/resolvers.rb +16 -10
- data/lib/sprockets/railtie.rb +100 -0
- metadata +162 -140
- checksums.yaml +0 -7
- data/lib/action_controller/deprecated/base.rb +0 -143
- data/lib/action_controller/deprecated/dispatcher.rb +0 -28
- data/lib/action_controller/deprecated/url_writer.rb +0 -14
- data/lib/action_dispatch/routing/deprecated_mapper.rb +0 -525
- data/lib/action_view/helpers/prototype_helper.rb +0 -851
- data/lib/action_view/helpers/raw_output_helper.rb +0 -18
- data/lib/action_view/helpers/scriptaculous_helper.rb +0 -263
- data/lib/action_view/render/layouts.rb +0 -83
- data/lib/action_view/render/rendering.rb +0 -67
- data/lib/action_view/template/handlers/rjs.rb +0 -17
@@ -0,0 +1,54 @@
|
|
1
|
+
module ActionView
|
2
|
+
# This is the main entry point for rendering. It basically delegates
|
3
|
+
# to other objects like TemplateRenderer and PartialRenderer which
|
4
|
+
# actually renders the template.
|
5
|
+
class Renderer
|
6
|
+
attr_accessor :lookup_context
|
7
|
+
|
8
|
+
def initialize(lookup_context)
|
9
|
+
@lookup_context = lookup_context
|
10
|
+
end
|
11
|
+
|
12
|
+
# Main render entry point shared by AV and AC.
|
13
|
+
def render(context, options)
|
14
|
+
if options.key?(:partial)
|
15
|
+
render_partial(context, options)
|
16
|
+
else
|
17
|
+
render_template(context, options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Render but returns a valid Rack body. If fibers are defined, we return
|
22
|
+
# a streaming body that renders the template piece by piece.
|
23
|
+
#
|
24
|
+
# Note that partials are not supported to be rendered with streaming,
|
25
|
+
# so in such cases, we just wrap them in an array.
|
26
|
+
def render_body(context, options)
|
27
|
+
if options.key?(:partial)
|
28
|
+
[render_partial(context, options)]
|
29
|
+
else
|
30
|
+
StreamingTemplateRenderer.new(@lookup_context).render(context, options)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Direct accessor to template rendering.
|
35
|
+
def render_template(context, options) #:nodoc:
|
36
|
+
_template_renderer.render(context, options)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Direct access to partial rendering.
|
40
|
+
def render_partial(context, options, &block) #:nodoc:
|
41
|
+
_partial_renderer.render(context, options, block)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def _template_renderer #:nodoc:
|
47
|
+
@_template_renderer ||= TemplateRenderer.new(@lookup_context)
|
48
|
+
end
|
49
|
+
|
50
|
+
def _partial_renderer #:nodoc:
|
51
|
+
@_partial_renderer ||= PartialRenderer.new(@lookup_context)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# 1.9 ships with Fibers but we need to require the extra
|
2
|
+
# methods explicitly. We only load those extra methods if
|
3
|
+
# Fiber is available in the first place.
|
4
|
+
require 'fiber' if defined?(Fiber)
|
5
|
+
|
6
|
+
module ActionView
|
7
|
+
# == TODO
|
8
|
+
#
|
9
|
+
# * Support streaming from child templates, partials and so on.
|
10
|
+
# * Integrate exceptions with exceptron
|
11
|
+
# * Rack::Cache needs to support streaming bodies
|
12
|
+
class StreamingTemplateRenderer < TemplateRenderer #:nodoc:
|
13
|
+
# A valid Rack::Body (i.e. it responds to each).
|
14
|
+
# It is initialized with a block that, when called, starts
|
15
|
+
# rendering the template.
|
16
|
+
class Body #:nodoc:
|
17
|
+
def initialize(&start)
|
18
|
+
@start = start
|
19
|
+
end
|
20
|
+
|
21
|
+
def each(&block)
|
22
|
+
begin
|
23
|
+
@start.call(block)
|
24
|
+
rescue Exception => exception
|
25
|
+
log_error(exception)
|
26
|
+
block.call ActionView::Base.streaming_completion_on_exception
|
27
|
+
end
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# This is the same logging logic as in ShowExceptions middleware.
|
34
|
+
# TODO Once "exceptron" is in, refactor this piece to simply re-use exceptron.
|
35
|
+
def log_error(exception) #:nodoc:
|
36
|
+
logger = ActionController::Base.logger
|
37
|
+
return unless logger
|
38
|
+
|
39
|
+
message = "\n#{exception.class} (#{exception.message}):\n"
|
40
|
+
message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
|
41
|
+
message << " " << exception.backtrace.join("\n ")
|
42
|
+
logger.fatal("#{message}\n\n")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# For streaming, instead of rendering a given a template, we return a Body
|
47
|
+
# object that responds to each. This object is initialized with a block
|
48
|
+
# that knows how to render the template.
|
49
|
+
def render_template(template, layout_name = nil, locals = {}) #:nodoc:
|
50
|
+
return [super] unless layout_name && template.supports_streaming?
|
51
|
+
|
52
|
+
locals ||= {}
|
53
|
+
layout = layout_name && find_layout(layout_name, locals.keys)
|
54
|
+
|
55
|
+
Body.new do |buffer|
|
56
|
+
delayed_render(buffer, template, layout, @view, locals)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def delayed_render(buffer, template, layout, view, locals)
|
63
|
+
# Wrap the given buffer in the StreamingBuffer and pass it to the
|
64
|
+
# underlying template handler. Now, everytime something is concatenated
|
65
|
+
# to the buffer, it is not appended to an array, but streamed straight
|
66
|
+
# to the client.
|
67
|
+
output = ActionView::StreamingBuffer.new(buffer)
|
68
|
+
yielder = lambda { |*name| view._layout_for(*name) }
|
69
|
+
|
70
|
+
instrument(:template, :identifier => template.identifier, :layout => layout.try(:virtual_path)) do
|
71
|
+
fiber = Fiber.new do
|
72
|
+
if layout
|
73
|
+
layout.render(view, locals, output, &yielder)
|
74
|
+
else
|
75
|
+
# If you don't have a layout, just render the thing
|
76
|
+
# and concatenate the final result. This is the same
|
77
|
+
# as a layout with just <%= yield %>
|
78
|
+
output.safe_concat view._layout_for
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Set the view flow to support streaming. It will be aware
|
83
|
+
# when to stop rendering the layout because it needs to search
|
84
|
+
# something in the template and vice-versa.
|
85
|
+
view.view_flow = StreamingFlow.new(view, fiber)
|
86
|
+
|
87
|
+
# Yo! Start the fiber!
|
88
|
+
fiber.resume
|
89
|
+
|
90
|
+
# If the fiber is still alive, it means we need something
|
91
|
+
# from the template, so start rendering it. If not, it means
|
92
|
+
# the layout exited without requiring anything from the template.
|
93
|
+
if fiber.alive?
|
94
|
+
content = template.render(view, locals, &yielder)
|
95
|
+
|
96
|
+
# Once rendering the template is done, sets its content in the :layout key.
|
97
|
+
view.view_flow.set(:layout, content)
|
98
|
+
|
99
|
+
# In case the layout continues yielding, we need to resume
|
100
|
+
# the fiber until all yields are handled.
|
101
|
+
fiber.resume while fiber.alive?
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'active_support/core_ext/object/try'
|
2
|
+
require 'active_support/core_ext/array/wrap'
|
3
|
+
|
4
|
+
module ActionView
|
5
|
+
class TemplateRenderer < AbstractRenderer #:nodoc:
|
6
|
+
def render(context, options)
|
7
|
+
@view = context
|
8
|
+
|
9
|
+
wrap_formats(options[:template] || options[:file]) do
|
10
|
+
template = determine_template(options)
|
11
|
+
freeze_formats(template.formats, true)
|
12
|
+
render_template(template, options[:layout], options[:locals])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Determine the template to be rendered using the given options.
|
17
|
+
def determine_template(options) #:nodoc:
|
18
|
+
keys = options[:locals].try(:keys) || []
|
19
|
+
|
20
|
+
if options.key?(:text)
|
21
|
+
Template::Text.new(options[:text], formats.try(:first))
|
22
|
+
elsif options.key?(:file)
|
23
|
+
with_fallbacks { find_template(options[:file], nil, false, keys) }
|
24
|
+
elsif options.key?(:inline)
|
25
|
+
handler = Template.handler_for_extension(options[:type] || "erb")
|
26
|
+
Template.new(options[:inline], "inline template", handler, :locals => keys)
|
27
|
+
elsif options.key?(:template)
|
28
|
+
options[:template].respond_to?(:render) ?
|
29
|
+
options[:template] : find_template(options[:template], options[:prefixes], false, keys)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Renders the given template. An string representing the layout can be
|
34
|
+
# supplied as well.
|
35
|
+
def render_template(template, layout_name = nil, locals = {}) #:nodoc:
|
36
|
+
view, locals = @view, locals || {}
|
37
|
+
|
38
|
+
render_with_layout(layout_name, locals) do |layout|
|
39
|
+
instrument(:template, :identifier => template.identifier, :layout => layout.try(:virtual_path)) do
|
40
|
+
template.render(view, locals) { |*name| view._layout_for(*name) }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def render_with_layout(path, locals) #:nodoc:
|
46
|
+
layout = path && find_layout(path, locals.keys)
|
47
|
+
content = yield(layout)
|
48
|
+
|
49
|
+
if layout
|
50
|
+
view = @view
|
51
|
+
view.view_flow.set(:layout, content)
|
52
|
+
layout.render(view, locals){ |*name| view._layout_for(*name) }
|
53
|
+
else
|
54
|
+
content
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# This is the method which actually finds the layout using details in the lookup
|
59
|
+
# context object. If no layout is found, it checks if at least a layout with
|
60
|
+
# the given name exists across all details before raising the error.
|
61
|
+
def find_layout(layout, keys)
|
62
|
+
begin
|
63
|
+
with_layout_format do
|
64
|
+
layout =~ /^\// ?
|
65
|
+
with_fallbacks { find_template(layout, nil, false, keys) } : find_template(layout, nil, false, keys)
|
66
|
+
end
|
67
|
+
rescue ActionView::MissingTemplate => e
|
68
|
+
update_details(:formats => nil) do
|
69
|
+
raise unless template_exists?(layout)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/action_view/template.rb
CHANGED
@@ -98,9 +98,12 @@ module ActionView
|
|
98
98
|
|
99
99
|
extend Template::Handlers
|
100
100
|
|
101
|
-
|
102
|
-
:original_encoding
|
101
|
+
attr_accessor :locals, :formats, :virtual_path
|
103
102
|
|
103
|
+
attr_reader :source, :identifier, :handler, :original_encoding, :updated_at
|
104
|
+
|
105
|
+
# This finalizer is needed (and exactly with a proc inside another proc)
|
106
|
+
# otherwise templates leak in development.
|
104
107
|
Finalizer = proc do |method_name, mod|
|
105
108
|
proc do
|
106
109
|
mod.module_eval do
|
@@ -110,61 +113,88 @@ module ActionView
|
|
110
113
|
end
|
111
114
|
|
112
115
|
def initialize(source, identifier, handler, details)
|
113
|
-
|
114
|
-
@identifier = identifier
|
115
|
-
@handler = handler
|
116
|
-
@original_encoding = nil
|
117
|
-
@method_names = {}
|
116
|
+
format = details[:format] || (handler.default_format if handler.respond_to?(:default_format))
|
118
117
|
|
119
|
-
|
118
|
+
@source = source
|
119
|
+
@identifier = identifier
|
120
|
+
@handler = handler
|
121
|
+
@compiled = false
|
122
|
+
@original_encoding = nil
|
123
|
+
@locals = details[:locals] || []
|
124
|
+
@virtual_path = details[:virtual_path]
|
125
|
+
@updated_at = details[:updated_at] || Time.now
|
120
126
|
@formats = Array.wrap(format).map { |f| f.is_a?(Mime::Type) ? f.ref : f }
|
121
|
-
@virtual_path = details[:virtual_path].try(:sub, ".#{format}", "")
|
122
127
|
end
|
123
128
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
mod = ActionView::CompiledTemplates
|
130
|
-
else
|
131
|
-
mod = view.singleton_class
|
132
|
-
end
|
129
|
+
# Returns if the underlying handler supports streaming. If so,
|
130
|
+
# a streaming buffer *may* be passed when it start rendering.
|
131
|
+
def supports_streaming?
|
132
|
+
handler.respond_to?(:supports_streaming?) && handler.supports_streaming?
|
133
|
+
end
|
133
134
|
|
134
|
-
|
135
|
-
|
135
|
+
# Render a template. If the template was not compiled yet, it is done
|
136
|
+
# exactly before rendering.
|
137
|
+
#
|
138
|
+
# This method is instrumented as "!render_template.action_view". Notice that
|
139
|
+
# we use a bang in this instrumentation because you don't want to
|
140
|
+
# consume this in production. This is only slow if it's being listened to.
|
141
|
+
def render(view, locals, buffer=nil, &block)
|
142
|
+
ActiveSupport::Notifications.instrument("!render_template.action_view", :virtual_path => @virtual_path) do
|
143
|
+
compile!(view)
|
144
|
+
view.send(method_name, locals, buffer, &block)
|
136
145
|
end
|
137
146
|
rescue Exception => e
|
138
|
-
|
139
|
-
e.sub_template_of(self)
|
140
|
-
raise e
|
141
|
-
else
|
142
|
-
raise Template::Error.new(self, view.respond_to?(:assigns) ? view.assigns : {}, e)
|
143
|
-
end
|
147
|
+
handle_render_error(view, e)
|
144
148
|
end
|
145
149
|
|
146
150
|
def mime_type
|
147
151
|
@mime_type ||= Mime::Type.lookup_by_extension(@formats.first.to_s) if @formats.first
|
148
152
|
end
|
149
153
|
|
150
|
-
|
151
|
-
|
154
|
+
# Receives a view object and return a template similar to self by using @virtual_path.
|
155
|
+
#
|
156
|
+
# This method is useful if you have a template object but it does not contain its source
|
157
|
+
# anymore since it was already compiled. In such cases, all you need to do is to call
|
158
|
+
# refresh passing in the view object.
|
159
|
+
#
|
160
|
+
# Notice this method raises an error if the template to be refreshed does not have a
|
161
|
+
# virtual path set (true just for inline templates).
|
162
|
+
def refresh(view)
|
163
|
+
raise "A template needs to have a virtual path in order to be refreshed" unless @virtual_path
|
164
|
+
lookup = view.lookup_context
|
165
|
+
pieces = @virtual_path.split("/")
|
166
|
+
name = pieces.pop
|
167
|
+
partial = !!name.sub!(/^_/, "")
|
168
|
+
lookup.disable_cache do
|
169
|
+
lookup.find_template(name, [ pieces.join('/') ], partial, @locals)
|
170
|
+
end
|
152
171
|
end
|
153
172
|
|
154
|
-
def
|
155
|
-
@
|
173
|
+
def inspect
|
174
|
+
@inspect ||= defined?(Rails.root) ? identifier.sub("#{Rails.root}/", '') : identifier
|
156
175
|
end
|
157
176
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
177
|
+
protected
|
178
|
+
|
179
|
+
# Compile a template. This method ensures a template is compiled
|
180
|
+
# just once and removes the source after it is compiled.
|
181
|
+
def compile!(view) #:nodoc:
|
182
|
+
return if @compiled
|
183
|
+
|
184
|
+
if view.is_a?(ActionView::CompiledTemplates)
|
185
|
+
mod = ActionView::CompiledTemplates
|
162
186
|
else
|
163
|
-
|
187
|
+
mod = view.singleton_class
|
164
188
|
end
|
165
|
-
end
|
166
189
|
|
167
|
-
|
190
|
+
compile(view, mod)
|
191
|
+
|
192
|
+
# Just discard the source if we have a virtual path. This
|
193
|
+
# means we can get the template back.
|
194
|
+
@source = nil if @virtual_path
|
195
|
+
@compiled = true
|
196
|
+
end
|
197
|
+
|
168
198
|
# Among other things, this method is responsible for properly setting
|
169
199
|
# the encoding of the source. Until this point, we assume that the
|
170
200
|
# source is BINARY data. If no additional information is supplied,
|
@@ -185,16 +215,10 @@ module ActionView
|
|
185
215
|
# encode the source into Encoding.default_internal. In general,
|
186
216
|
# this means that templates will be UTF-8 inside of Rails,
|
187
217
|
# regardless of the original source encoding.
|
188
|
-
def compile(
|
189
|
-
method_name =
|
190
|
-
return method_name if view.respond_to?(method_name)
|
191
|
-
|
192
|
-
locals_code = locals.keys.map! { |key| "#{key} = local_assigns[:#{key}];" }.join
|
218
|
+
def compile(view, mod) #:nodoc:
|
219
|
+
method_name = self.method_name
|
193
220
|
|
194
221
|
if source.encoding_aware?
|
195
|
-
# Avoid performing in-place mutation for SafeBuffer
|
196
|
-
@source = source.to_str if source.html_safe?
|
197
|
-
|
198
222
|
# Look for # encoding: *. If we find one, we'll encode the
|
199
223
|
# String in that encoding, otherwise, we'll use the
|
200
224
|
# default external encoding.
|
@@ -231,10 +255,10 @@ module ActionView
|
|
231
255
|
# Make sure that the resulting String to be evalled is in the
|
232
256
|
# encoding of the code
|
233
257
|
source = <<-end_src
|
234
|
-
def #{method_name}(local_assigns)
|
235
|
-
_old_virtual_path, @
|
258
|
+
def #{method_name}(local_assigns, output_buffer)
|
259
|
+
_old_virtual_path, @virtual_path = @virtual_path, #{@virtual_path.inspect};_old_output_buffer = @output_buffer;#{locals_code};#{code}
|
236
260
|
ensure
|
237
|
-
@
|
261
|
+
@virtual_path, @output_buffer = _old_virtual_path, _old_output_buffer
|
238
262
|
end
|
239
263
|
end_src
|
240
264
|
|
@@ -257,8 +281,6 @@ module ActionView
|
|
257
281
|
begin
|
258
282
|
mod.module_eval(source, identifier, 0)
|
259
283
|
ObjectSpace.define_finalizer(self, Finalizer[method_name, mod])
|
260
|
-
|
261
|
-
method_name
|
262
284
|
rescue Exception => e # errors from template code
|
263
285
|
if logger = (view && view.logger)
|
264
286
|
logger.debug "ERROR: compiling #{method_name} RAISED #{e}"
|
@@ -270,12 +292,27 @@ module ActionView
|
|
270
292
|
end
|
271
293
|
end
|
272
294
|
|
273
|
-
def
|
274
|
-
|
295
|
+
def handle_render_error(view, e) #:nodoc:
|
296
|
+
if e.is_a?(Template::Error)
|
297
|
+
e.sub_template_of(self)
|
298
|
+
raise e
|
299
|
+
else
|
300
|
+
assigns = view.respond_to?(:assigns) ? view.assigns : {}
|
301
|
+
template = @virtual_path ? refresh(view) : self
|
302
|
+
raise Template::Error.new(template, assigns, e)
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def locals_code #:nodoc:
|
307
|
+
@locals.map { |key| "#{key} = local_assigns[:#{key}];" }.join
|
308
|
+
end
|
309
|
+
|
310
|
+
def method_name #:nodoc:
|
311
|
+
@method_name ||= "_#{identifier_method_name}__#{@identifier.hash}_#{__id__}".gsub('-', "_")
|
275
312
|
end
|
276
313
|
|
277
|
-
def identifier_method_name
|
278
|
-
|
314
|
+
def identifier_method_name #:nodoc:
|
315
|
+
inspect.gsub(/[^a-z_]/, '_')
|
279
316
|
end
|
280
317
|
end
|
281
318
|
end
|
@@ -27,7 +27,7 @@ module ActionView
|
|
27
27
|
class MissingTemplate < ActionViewError #:nodoc:
|
28
28
|
attr_reader :path
|
29
29
|
|
30
|
-
def initialize(paths, path, details,
|
30
|
+
def initialize(paths, path, prefixes, partial, details, *)
|
31
31
|
@path = path
|
32
32
|
display_paths = paths.compact.map{ |p| p.to_s.inspect }.join(", ")
|
33
33
|
template_type = if partial
|
@@ -38,20 +38,27 @@ module ActionView
|
|
38
38
|
'template'
|
39
39
|
end
|
40
40
|
|
41
|
-
|
41
|
+
searched_paths = prefixes.map { |prefix| [prefix, path].join("/") }
|
42
|
+
|
43
|
+
out = "Missing #{template_type} #{searched_paths.join(", ")} with #{details.inspect}. Searched in:\n"
|
44
|
+
out += paths.compact.map { |p| " * #{p.to_s.inspect}\n" }.join
|
45
|
+
super out
|
42
46
|
end
|
43
47
|
end
|
44
48
|
|
45
49
|
class Template
|
46
|
-
# The Template::Error exception is raised when the compilation of the template
|
47
|
-
# bunch of intimate details and uses it to report a
|
50
|
+
# The Template::Error exception is raised when the compilation or rendering of the template
|
51
|
+
# fails. This exception then gathers a bunch of intimate details and uses it to report a
|
52
|
+
# precise exception message.
|
48
53
|
class Error < ActionViewError #:nodoc:
|
49
54
|
SOURCE_CODE_RADIUS = 3
|
50
55
|
|
51
56
|
attr_reader :original_exception, :backtrace
|
52
57
|
|
53
58
|
def initialize(template, assigns, original_exception)
|
59
|
+
super(original_exception.message)
|
54
60
|
@template, @assigns, @original_exception = template, assigns.dup, original_exception
|
61
|
+
@sub_templates = nil
|
55
62
|
@backtrace = original_exception.backtrace
|
56
63
|
end
|
57
64
|
|
@@ -59,10 +66,6 @@ module ActionView
|
|
59
66
|
@template.identifier
|
60
67
|
end
|
61
68
|
|
62
|
-
def message
|
63
|
-
ActiveSupport::Deprecation.silence { original_exception.message }
|
64
|
-
end
|
65
|
-
|
66
69
|
def sub_template_message
|
67
70
|
if @sub_templates
|
68
71
|
"Trace of template inclusion: " +
|