actionview 4.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 actionview might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/CHANGELOG.md +274 -0
- data/MIT-LICENSE +21 -0
- data/README.rdoc +34 -0
- data/lib/action_view.rb +97 -0
- data/lib/action_view/base.rb +205 -0
- data/lib/action_view/buffers.rb +49 -0
- data/lib/action_view/context.rb +36 -0
- data/lib/action_view/dependency_tracker.rb +93 -0
- data/lib/action_view/digestor.rb +116 -0
- data/lib/action_view/flows.rb +76 -0
- data/lib/action_view/helpers.rb +64 -0
- data/lib/action_view/helpers/active_model_helper.rb +49 -0
- data/lib/action_view/helpers/asset_tag_helper.rb +322 -0
- data/lib/action_view/helpers/asset_url_helper.rb +355 -0
- data/lib/action_view/helpers/atom_feed_helper.rb +203 -0
- data/lib/action_view/helpers/cache_helper.rb +200 -0
- data/lib/action_view/helpers/capture_helper.rb +216 -0
- data/lib/action_view/helpers/controller_helper.rb +25 -0
- data/lib/action_view/helpers/csrf_helper.rb +30 -0
- data/lib/action_view/helpers/date_helper.rb +1075 -0
- data/lib/action_view/helpers/debug_helper.rb +39 -0
- data/lib/action_view/helpers/form_helper.rb +1876 -0
- data/lib/action_view/helpers/form_options_helper.rb +843 -0
- data/lib/action_view/helpers/form_tag_helper.rb +746 -0
- data/lib/action_view/helpers/javascript_helper.rb +75 -0
- data/lib/action_view/helpers/number_helper.rb +425 -0
- data/lib/action_view/helpers/output_safety_helper.rb +38 -0
- data/lib/action_view/helpers/record_tag_helper.rb +108 -0
- data/lib/action_view/helpers/rendering_helper.rb +90 -0
- data/lib/action_view/helpers/sanitize_helper.rb +256 -0
- data/lib/action_view/helpers/tag_helper.rb +176 -0
- data/lib/action_view/helpers/tags.rb +41 -0
- data/lib/action_view/helpers/tags/base.rb +148 -0
- data/lib/action_view/helpers/tags/check_box.rb +64 -0
- data/lib/action_view/helpers/tags/checkable.rb +16 -0
- data/lib/action_view/helpers/tags/collection_check_boxes.rb +44 -0
- data/lib/action_view/helpers/tags/collection_helpers.rb +85 -0
- data/lib/action_view/helpers/tags/collection_radio_buttons.rb +36 -0
- data/lib/action_view/helpers/tags/collection_select.rb +28 -0
- data/lib/action_view/helpers/tags/color_field.rb +25 -0
- data/lib/action_view/helpers/tags/date_field.rb +13 -0
- data/lib/action_view/helpers/tags/date_select.rb +72 -0
- data/lib/action_view/helpers/tags/datetime_field.rb +22 -0
- data/lib/action_view/helpers/tags/datetime_local_field.rb +19 -0
- data/lib/action_view/helpers/tags/datetime_select.rb +8 -0
- data/lib/action_view/helpers/tags/email_field.rb +8 -0
- data/lib/action_view/helpers/tags/file_field.rb +8 -0
- data/lib/action_view/helpers/tags/grouped_collection_select.rb +29 -0
- data/lib/action_view/helpers/tags/hidden_field.rb +8 -0
- data/lib/action_view/helpers/tags/label.rb +65 -0
- data/lib/action_view/helpers/tags/month_field.rb +13 -0
- data/lib/action_view/helpers/tags/number_field.rb +18 -0
- data/lib/action_view/helpers/tags/password_field.rb +12 -0
- data/lib/action_view/helpers/tags/radio_button.rb +31 -0
- data/lib/action_view/helpers/tags/range_field.rb +8 -0
- data/lib/action_view/helpers/tags/search_field.rb +24 -0
- data/lib/action_view/helpers/tags/select.rb +41 -0
- data/lib/action_view/helpers/tags/tel_field.rb +8 -0
- data/lib/action_view/helpers/tags/text_area.rb +18 -0
- data/lib/action_view/helpers/tags/text_field.rb +29 -0
- data/lib/action_view/helpers/tags/time_field.rb +13 -0
- data/lib/action_view/helpers/tags/time_select.rb +8 -0
- data/lib/action_view/helpers/tags/time_zone_select.rb +20 -0
- data/lib/action_view/helpers/tags/url_field.rb +8 -0
- data/lib/action_view/helpers/tags/week_field.rb +13 -0
- data/lib/action_view/helpers/text_helper.rb +447 -0
- data/lib/action_view/helpers/translation_helper.rb +111 -0
- data/lib/action_view/helpers/url_helper.rb +625 -0
- data/lib/action_view/layouts.rb +426 -0
- data/lib/action_view/locale/en.yml +56 -0
- data/lib/action_view/log_subscriber.rb +44 -0
- data/lib/action_view/lookup_context.rb +249 -0
- data/lib/action_view/model_naming.rb +12 -0
- data/lib/action_view/path_set.rb +77 -0
- data/lib/action_view/railtie.rb +49 -0
- data/lib/action_view/record_identifier.rb +84 -0
- data/lib/action_view/renderer/abstract_renderer.rb +47 -0
- data/lib/action_view/renderer/partial_renderer.rb +492 -0
- data/lib/action_view/renderer/renderer.rb +50 -0
- data/lib/action_view/renderer/streaming_template_renderer.rb +103 -0
- data/lib/action_view/renderer/template_renderer.rb +96 -0
- data/lib/action_view/rendering.rb +145 -0
- data/lib/action_view/routing_url_for.rb +109 -0
- data/lib/action_view/tasks/dependencies.rake +17 -0
- data/lib/action_view/template.rb +340 -0
- data/lib/action_view/template/error.rb +141 -0
- data/lib/action_view/template/handlers.rb +53 -0
- data/lib/action_view/template/handlers/builder.rb +26 -0
- data/lib/action_view/template/handlers/erb.rb +145 -0
- data/lib/action_view/template/handlers/raw.rb +11 -0
- data/lib/action_view/template/resolver.rb +329 -0
- data/lib/action_view/template/text.rb +34 -0
- data/lib/action_view/template/types.rb +57 -0
- data/lib/action_view/test_case.rb +272 -0
- data/lib/action_view/testing/resolvers.rb +50 -0
- data/lib/action_view/vendor/html-scanner.rb +20 -0
- data/lib/action_view/vendor/html-scanner/html/document.rb +68 -0
- data/lib/action_view/vendor/html-scanner/html/node.rb +532 -0
- data/lib/action_view/vendor/html-scanner/html/sanitizer.rb +188 -0
- data/lib/action_view/vendor/html-scanner/html/selector.rb +830 -0
- data/lib/action_view/vendor/html-scanner/html/tokenizer.rb +107 -0
- data/lib/action_view/vendor/html-scanner/html/version.rb +11 -0
- data/lib/action_view/version.rb +11 -0
- data/lib/action_view/view_paths.rb +96 -0
- metadata +218 -0
@@ -0,0 +1,50 @@
|
|
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
|
+
#
|
6
|
+
# The Renderer will parse the options from the +render+ or +render_body+
|
7
|
+
# method and render a partial or a template based on the options. The
|
8
|
+
# +TemplateRenderer+ and +PartialRenderer+ objects are wrappers which do all
|
9
|
+
# the setup and logic necessary to render a view and a new object is created
|
10
|
+
# each time +render+ is called.
|
11
|
+
class Renderer
|
12
|
+
attr_accessor :lookup_context
|
13
|
+
|
14
|
+
def initialize(lookup_context)
|
15
|
+
@lookup_context = lookup_context
|
16
|
+
end
|
17
|
+
|
18
|
+
# Main render entry point shared by AV and AC.
|
19
|
+
def render(context, options)
|
20
|
+
if options.key?(:partial)
|
21
|
+
render_partial(context, options)
|
22
|
+
else
|
23
|
+
render_template(context, options)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Render but returns a valid Rack body. If fibers are defined, we return
|
28
|
+
# a streaming body that renders the template piece by piece.
|
29
|
+
#
|
30
|
+
# Note that partials are not supported to be rendered with streaming,
|
31
|
+
# so in such cases, we just wrap them in an array.
|
32
|
+
def render_body(context, options)
|
33
|
+
if options.key?(:partial)
|
34
|
+
[render_partial(context, options)]
|
35
|
+
else
|
36
|
+
StreamingTemplateRenderer.new(@lookup_context).render(context, options)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Direct accessor to template rendering.
|
41
|
+
def render_template(context, options) #:nodoc:
|
42
|
+
TemplateRenderer.new(@lookup_context).render(context, options)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Direct access to partial rendering.
|
46
|
+
def render_partial(context, options, &block) #:nodoc:
|
47
|
+
PartialRenderer.new(@lookup_context).render(context, options, block)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'fiber'
|
2
|
+
|
3
|
+
module ActionView
|
4
|
+
# == TODO
|
5
|
+
#
|
6
|
+
# * Support streaming from child templates, partials and so on.
|
7
|
+
# * Integrate exceptions with exceptron
|
8
|
+
# * Rack::Cache needs to support streaming bodies
|
9
|
+
class StreamingTemplateRenderer < TemplateRenderer #:nodoc:
|
10
|
+
# A valid Rack::Body (i.e. it responds to each).
|
11
|
+
# It is initialized with a block that, when called, starts
|
12
|
+
# rendering the template.
|
13
|
+
class Body #:nodoc:
|
14
|
+
def initialize(&start)
|
15
|
+
@start = start
|
16
|
+
end
|
17
|
+
|
18
|
+
def each(&block)
|
19
|
+
begin
|
20
|
+
@start.call(block)
|
21
|
+
rescue Exception => exception
|
22
|
+
log_error(exception)
|
23
|
+
block.call ActionView::Base.streaming_completion_on_exception
|
24
|
+
end
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# This is the same logging logic as in ShowExceptions middleware.
|
31
|
+
# TODO Once "exceptron" is in, refactor this piece to simply re-use exceptron.
|
32
|
+
def log_error(exception) #:nodoc:
|
33
|
+
logger = ActionView::Base.logger
|
34
|
+
return unless logger
|
35
|
+
|
36
|
+
message = "\n#{exception.class} (#{exception.message}):\n"
|
37
|
+
message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
|
38
|
+
message << " " << exception.backtrace.join("\n ")
|
39
|
+
logger.fatal("#{message}\n\n")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# For streaming, instead of rendering a given a template, we return a Body
|
44
|
+
# object that responds to each. This object is initialized with a block
|
45
|
+
# that knows how to render the template.
|
46
|
+
def render_template(template, layout_name = nil, locals = {}) #:nodoc:
|
47
|
+
return [super] unless layout_name && template.supports_streaming?
|
48
|
+
|
49
|
+
locals ||= {}
|
50
|
+
layout = layout_name && find_layout(layout_name, locals.keys)
|
51
|
+
|
52
|
+
Body.new do |buffer|
|
53
|
+
delayed_render(buffer, template, layout, @view, locals)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def delayed_render(buffer, template, layout, view, locals)
|
60
|
+
# Wrap the given buffer in the StreamingBuffer and pass it to the
|
61
|
+
# underlying template handler. Now, every time something is concatenated
|
62
|
+
# to the buffer, it is not appended to an array, but streamed straight
|
63
|
+
# to the client.
|
64
|
+
output = ActionView::StreamingBuffer.new(buffer)
|
65
|
+
yielder = lambda { |*name| view._layout_for(*name) }
|
66
|
+
|
67
|
+
instrument(:template, :identifier => template.identifier, :layout => layout.try(:virtual_path)) do
|
68
|
+
fiber = Fiber.new do
|
69
|
+
if layout
|
70
|
+
layout.render(view, locals, output, &yielder)
|
71
|
+
else
|
72
|
+
# If you don't have a layout, just render the thing
|
73
|
+
# and concatenate the final result. This is the same
|
74
|
+
# as a layout with just <%= yield %>
|
75
|
+
output.safe_concat view._layout_for
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# Set the view flow to support streaming. It will be aware
|
80
|
+
# when to stop rendering the layout because it needs to search
|
81
|
+
# something in the template and vice-versa.
|
82
|
+
view.view_flow = StreamingFlow.new(view, fiber)
|
83
|
+
|
84
|
+
# Yo! Start the fiber!
|
85
|
+
fiber.resume
|
86
|
+
|
87
|
+
# If the fiber is still alive, it means we need something
|
88
|
+
# from the template, so start rendering it. If not, it means
|
89
|
+
# the layout exited without requiring anything from the template.
|
90
|
+
if fiber.alive?
|
91
|
+
content = template.render(view, locals, &yielder)
|
92
|
+
|
93
|
+
# Once rendering the template is done, sets its content in the :layout key.
|
94
|
+
view.view_flow.set(:layout, content)
|
95
|
+
|
96
|
+
# In case the layout continues yielding, we need to resume
|
97
|
+
# the fiber until all yields are handled.
|
98
|
+
fiber.resume while fiber.alive?
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'active_support/core_ext/object/try'
|
2
|
+
|
3
|
+
module ActionView
|
4
|
+
class TemplateRenderer < AbstractRenderer #:nodoc:
|
5
|
+
def render(context, options)
|
6
|
+
@view = context
|
7
|
+
@details = extract_details(options)
|
8
|
+
template = determine_template(options)
|
9
|
+
context = @lookup_context
|
10
|
+
|
11
|
+
prepend_formats(template.formats)
|
12
|
+
|
13
|
+
unless context.rendered_format
|
14
|
+
context.rendered_format = template.formats.first || formats.first
|
15
|
+
end
|
16
|
+
|
17
|
+
render_template(template, options[:layout], options[:locals])
|
18
|
+
end
|
19
|
+
|
20
|
+
# Determine the template to be rendered using the given options.
|
21
|
+
def determine_template(options) #:nodoc:
|
22
|
+
keys = options.fetch(:locals, {}).keys
|
23
|
+
|
24
|
+
if options.key?(:text)
|
25
|
+
Template::Text.new(options[:text], formats.first)
|
26
|
+
elsif options.key?(:file)
|
27
|
+
with_fallbacks { find_template(options[:file], nil, false, keys, @details) }
|
28
|
+
elsif options.key?(:inline)
|
29
|
+
handler = Template.handler_for_extension(options[:type] || "erb")
|
30
|
+
Template.new(options[:inline], "inline template", handler, :locals => keys)
|
31
|
+
elsif options.key?(:template)
|
32
|
+
if options[:template].respond_to?(:render)
|
33
|
+
options[:template]
|
34
|
+
else
|
35
|
+
find_template(options[:template], options[:prefixes], false, keys, @details)
|
36
|
+
end
|
37
|
+
else
|
38
|
+
raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file or :text option."
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Renders the given template. A string representing the layout can be
|
43
|
+
# supplied as well.
|
44
|
+
def render_template(template, layout_name = nil, locals = nil) #:nodoc:
|
45
|
+
view, locals = @view, locals || {}
|
46
|
+
|
47
|
+
render_with_layout(layout_name, locals) do |layout|
|
48
|
+
instrument(:template, :identifier => template.identifier, :layout => layout.try(:virtual_path)) do
|
49
|
+
template.render(view, locals) { |*name| view._layout_for(*name) }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def render_with_layout(path, locals) #:nodoc:
|
55
|
+
layout = path && find_layout(path, locals.keys)
|
56
|
+
content = yield(layout)
|
57
|
+
|
58
|
+
if layout
|
59
|
+
view = @view
|
60
|
+
view.view_flow.set(:layout, content)
|
61
|
+
layout.render(view, locals){ |*name| view._layout_for(*name) }
|
62
|
+
else
|
63
|
+
content
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# This is the method which actually finds the layout using details in the lookup
|
68
|
+
# context object. If no layout is found, it checks if at least a layout with
|
69
|
+
# the given name exists across all details before raising the error.
|
70
|
+
def find_layout(layout, keys)
|
71
|
+
with_layout_format { resolve_layout(layout, keys) }
|
72
|
+
end
|
73
|
+
|
74
|
+
def resolve_layout(layout, keys)
|
75
|
+
case layout
|
76
|
+
when String
|
77
|
+
begin
|
78
|
+
if layout =~ /^\//
|
79
|
+
with_fallbacks { find_template(layout, nil, false, keys, @details) }
|
80
|
+
else
|
81
|
+
find_template(layout, nil, false, keys, @details)
|
82
|
+
end
|
83
|
+
rescue ActionView::MissingTemplate
|
84
|
+
all_details = @details.merge(:formats => @lookup_context.default_formats)
|
85
|
+
raise unless template_exists?(layout, nil, false, keys, all_details)
|
86
|
+
end
|
87
|
+
when Proc
|
88
|
+
resolve_layout(layout.call, keys)
|
89
|
+
when FalseClass
|
90
|
+
nil
|
91
|
+
else
|
92
|
+
layout
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require "action_view/view_paths"
|
2
|
+
|
3
|
+
module ActionView
|
4
|
+
# This is a class to fix I18n global state. Whenever you provide I18n.locale during a request,
|
5
|
+
# it will trigger the lookup_context and consequently expire the cache.
|
6
|
+
class I18nProxy < ::I18n::Config #:nodoc:
|
7
|
+
attr_reader :original_config, :lookup_context
|
8
|
+
|
9
|
+
def initialize(original_config, lookup_context)
|
10
|
+
original_config = original_config.original_config if original_config.respond_to?(:original_config)
|
11
|
+
@original_config, @lookup_context = original_config, lookup_context
|
12
|
+
end
|
13
|
+
|
14
|
+
def locale
|
15
|
+
@original_config.locale
|
16
|
+
end
|
17
|
+
|
18
|
+
def locale=(value)
|
19
|
+
@lookup_context.locale = value
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module Rendering
|
24
|
+
extend ActiveSupport::Concern
|
25
|
+
include ActionView::ViewPaths
|
26
|
+
|
27
|
+
# Overwrite process to setup I18n proxy.
|
28
|
+
def process(*) #:nodoc:
|
29
|
+
old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context)
|
30
|
+
super
|
31
|
+
ensure
|
32
|
+
I18n.config = old_config
|
33
|
+
end
|
34
|
+
|
35
|
+
module ClassMethods
|
36
|
+
def view_context_class
|
37
|
+
@view_context_class ||= begin
|
38
|
+
routes = respond_to?(:_routes) && _routes
|
39
|
+
helpers = respond_to?(:_helpers) && _helpers
|
40
|
+
|
41
|
+
Class.new(ActionView::Base) do
|
42
|
+
if routes
|
43
|
+
include routes.url_helpers
|
44
|
+
include routes.mounted_helpers
|
45
|
+
end
|
46
|
+
|
47
|
+
if helpers
|
48
|
+
include helpers
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
attr_internal_writer :view_context_class
|
56
|
+
|
57
|
+
def view_context_class
|
58
|
+
@_view_context_class ||= self.class.view_context_class
|
59
|
+
end
|
60
|
+
|
61
|
+
# An instance of a view class. The default view class is ActionView::Base
|
62
|
+
#
|
63
|
+
# The view class must have the following methods:
|
64
|
+
# View.new[lookup_context, assigns, controller]
|
65
|
+
# Create a new ActionView instance for a controller
|
66
|
+
# View#render[options]
|
67
|
+
# Returns String with the rendered template
|
68
|
+
#
|
69
|
+
# Override this method in a module to change the default behavior.
|
70
|
+
def view_context
|
71
|
+
view_context_class.new(view_renderer, view_assigns, self)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns an object that is able to render templates.
|
75
|
+
# :api: private
|
76
|
+
def view_renderer
|
77
|
+
@_view_renderer ||= ActionView::Renderer.new(lookup_context)
|
78
|
+
end
|
79
|
+
|
80
|
+
def render_to_body(options = {})
|
81
|
+
_process_options(options)
|
82
|
+
_render_template(options)
|
83
|
+
end
|
84
|
+
|
85
|
+
def rendered_format
|
86
|
+
Mime[lookup_context.rendered_format]
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
# Find and render a template based on the options given.
|
92
|
+
# :api: private
|
93
|
+
def _render_template(options) #:nodoc:
|
94
|
+
variant = options[:variant]
|
95
|
+
|
96
|
+
lookup_context.rendered_format = nil if options[:formats]
|
97
|
+
lookup_context.variants = [variant] if variant
|
98
|
+
|
99
|
+
view_renderer.render(view_context, options)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Assign the rendered format to lookup context.
|
103
|
+
def _process_format(format) #:nodoc:
|
104
|
+
super
|
105
|
+
lookup_context.formats = [format.to_sym]
|
106
|
+
lookup_context.rendered_format = lookup_context.formats.first
|
107
|
+
end
|
108
|
+
|
109
|
+
# Normalize args by converting render "foo" to render :action => "foo" and
|
110
|
+
# render "foo/bar" to render :file => "foo/bar".
|
111
|
+
# :api: private
|
112
|
+
def _normalize_args(action=nil, options={})
|
113
|
+
options = super(action, options)
|
114
|
+
case action
|
115
|
+
when NilClass
|
116
|
+
when Hash
|
117
|
+
options = action
|
118
|
+
when String, Symbol
|
119
|
+
action = action.to_s
|
120
|
+
key = action.include?(?/) ? :file : :action
|
121
|
+
options[key] = action
|
122
|
+
else
|
123
|
+
options[:partial] = action
|
124
|
+
end
|
125
|
+
|
126
|
+
options
|
127
|
+
end
|
128
|
+
|
129
|
+
# Normalize options.
|
130
|
+
# :api: private
|
131
|
+
def _normalize_options(options)
|
132
|
+
options = super(options)
|
133
|
+
if options[:partial] == true
|
134
|
+
options[:partial] = action_name
|
135
|
+
end
|
136
|
+
|
137
|
+
if (options.keys & [:partial, :file, :template]).empty?
|
138
|
+
options[:prefixes] ||= _prefixes
|
139
|
+
end
|
140
|
+
|
141
|
+
options[:template] ||= (options[:action] || action_name).to_s
|
142
|
+
options
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module ActionView
|
2
|
+
module RoutingUrlFor
|
3
|
+
|
4
|
+
# Returns the URL for the set of +options+ provided. This takes the
|
5
|
+
# same options as +url_for+ in Action Controller (see the
|
6
|
+
# documentation for <tt>ActionController::Base#url_for</tt>). Note that by default
|
7
|
+
# <tt>:only_path</tt> is <tt>true</tt> so you'll get the relative "/controller/action"
|
8
|
+
# instead of the fully qualified URL like "http://example.com/controller/action".
|
9
|
+
#
|
10
|
+
# ==== Options
|
11
|
+
# * <tt>:anchor</tt> - Specifies the anchor name to be appended to the path.
|
12
|
+
# * <tt>:only_path</tt> - If true, returns the relative URL (omitting the protocol, host name, and port) (<tt>true</tt> by default unless <tt>:host</tt> is specified).
|
13
|
+
# * <tt>:trailing_slash</tt> - If true, adds a trailing slash, as in "/archive/2005/". Note that this
|
14
|
+
# is currently not recommended since it breaks caching.
|
15
|
+
# * <tt>:host</tt> - Overrides the default (current) host if provided.
|
16
|
+
# * <tt>:protocol</tt> - Overrides the default (current) protocol if provided.
|
17
|
+
# * <tt>:user</tt> - Inline HTTP authentication (only plucked out if <tt>:password</tt> is also present).
|
18
|
+
# * <tt>:password</tt> - Inline HTTP authentication (only plucked out if <tt>:user</tt> is also present).
|
19
|
+
#
|
20
|
+
# ==== Relying on named routes
|
21
|
+
#
|
22
|
+
# Passing a record (like an Active Record) instead of a hash as the options parameter will
|
23
|
+
# trigger the named route for that record. The lookup will happen on the name of the class. So passing a
|
24
|
+
# Workshop object will attempt to use the +workshop_path+ route. If you have a nested route, such as
|
25
|
+
# +admin_workshop_path+ you'll have to call that explicitly (it's impossible for +url_for+ to guess that route).
|
26
|
+
#
|
27
|
+
# ==== Implicit Controller Namespacing
|
28
|
+
#
|
29
|
+
# Controllers passed in using the +:controller+ option will retain their namespace unless it is an absolute one.
|
30
|
+
#
|
31
|
+
# ==== Examples
|
32
|
+
# <%= url_for(action: 'index') %>
|
33
|
+
# # => /blog/
|
34
|
+
#
|
35
|
+
# <%= url_for(action: 'find', controller: 'books') %>
|
36
|
+
# # => /books/find
|
37
|
+
#
|
38
|
+
# <%= url_for(action: 'login', controller: 'members', only_path: false, protocol: 'https') %>
|
39
|
+
# # => https://www.example.com/members/login/
|
40
|
+
#
|
41
|
+
# <%= url_for(action: 'play', anchor: 'player') %>
|
42
|
+
# # => /messages/play/#player
|
43
|
+
#
|
44
|
+
# <%= url_for(action: 'jump', anchor: 'tax&ship') %>
|
45
|
+
# # => /testing/jump/#tax&ship
|
46
|
+
#
|
47
|
+
# <%= url_for(Workshop.new) %>
|
48
|
+
# # relies on Workshop answering a persisted? call (and in this case returning false)
|
49
|
+
# # => /workshops
|
50
|
+
#
|
51
|
+
# <%= url_for(@workshop) %>
|
52
|
+
# # calls @workshop.to_param which by default returns the id
|
53
|
+
# # => /workshops/5
|
54
|
+
#
|
55
|
+
# # to_param can be re-defined in a model to provide different URL names:
|
56
|
+
# # => /workshops/1-workshop-name
|
57
|
+
#
|
58
|
+
# <%= url_for("http://www.example.com") %>
|
59
|
+
# # => http://www.example.com
|
60
|
+
#
|
61
|
+
# <%= url_for(:back) %>
|
62
|
+
# # if request.env["HTTP_REFERER"] is set to "http://www.example.com"
|
63
|
+
# # => http://www.example.com
|
64
|
+
#
|
65
|
+
# <%= url_for(:back) %>
|
66
|
+
# # if request.env["HTTP_REFERER"] is not set or is blank
|
67
|
+
# # => javascript:history.back()
|
68
|
+
#
|
69
|
+
# <%= url_for(action: 'index', controller: 'users') %>
|
70
|
+
# # Assuming an "admin" namespace
|
71
|
+
# # => /admin/users
|
72
|
+
#
|
73
|
+
# <%= url_for(action: 'index', controller: '/users') %>
|
74
|
+
# # Specify absolute path with beginning slash
|
75
|
+
# # => /users
|
76
|
+
def url_for(options = nil)
|
77
|
+
case options
|
78
|
+
when String
|
79
|
+
options
|
80
|
+
when nil, Hash
|
81
|
+
options ||= {}
|
82
|
+
options = { :only_path => options[:host].nil? }.merge!(options.symbolize_keys)
|
83
|
+
super
|
84
|
+
when :back
|
85
|
+
_back_url
|
86
|
+
when Array
|
87
|
+
polymorphic_path(options, options.extract_options!)
|
88
|
+
else
|
89
|
+
polymorphic_path(options)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def url_options #:nodoc:
|
94
|
+
return super unless controller.respond_to?(:url_options)
|
95
|
+
controller.url_options
|
96
|
+
end
|
97
|
+
|
98
|
+
def _routes_context #:nodoc:
|
99
|
+
controller
|
100
|
+
end
|
101
|
+
protected :_routes_context
|
102
|
+
|
103
|
+
def optimize_routes_generation? #:nodoc:
|
104
|
+
controller.respond_to?(:optimize_routes_generation?, true) ?
|
105
|
+
controller.optimize_routes_generation? : super
|
106
|
+
end
|
107
|
+
protected :optimize_routes_generation?
|
108
|
+
end
|
109
|
+
end
|