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.

Files changed (106) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +274 -0
  3. data/MIT-LICENSE +21 -0
  4. data/README.rdoc +34 -0
  5. data/lib/action_view.rb +97 -0
  6. data/lib/action_view/base.rb +205 -0
  7. data/lib/action_view/buffers.rb +49 -0
  8. data/lib/action_view/context.rb +36 -0
  9. data/lib/action_view/dependency_tracker.rb +93 -0
  10. data/lib/action_view/digestor.rb +116 -0
  11. data/lib/action_view/flows.rb +76 -0
  12. data/lib/action_view/helpers.rb +64 -0
  13. data/lib/action_view/helpers/active_model_helper.rb +49 -0
  14. data/lib/action_view/helpers/asset_tag_helper.rb +322 -0
  15. data/lib/action_view/helpers/asset_url_helper.rb +355 -0
  16. data/lib/action_view/helpers/atom_feed_helper.rb +203 -0
  17. data/lib/action_view/helpers/cache_helper.rb +200 -0
  18. data/lib/action_view/helpers/capture_helper.rb +216 -0
  19. data/lib/action_view/helpers/controller_helper.rb +25 -0
  20. data/lib/action_view/helpers/csrf_helper.rb +30 -0
  21. data/lib/action_view/helpers/date_helper.rb +1075 -0
  22. data/lib/action_view/helpers/debug_helper.rb +39 -0
  23. data/lib/action_view/helpers/form_helper.rb +1876 -0
  24. data/lib/action_view/helpers/form_options_helper.rb +843 -0
  25. data/lib/action_view/helpers/form_tag_helper.rb +746 -0
  26. data/lib/action_view/helpers/javascript_helper.rb +75 -0
  27. data/lib/action_view/helpers/number_helper.rb +425 -0
  28. data/lib/action_view/helpers/output_safety_helper.rb +38 -0
  29. data/lib/action_view/helpers/record_tag_helper.rb +108 -0
  30. data/lib/action_view/helpers/rendering_helper.rb +90 -0
  31. data/lib/action_view/helpers/sanitize_helper.rb +256 -0
  32. data/lib/action_view/helpers/tag_helper.rb +176 -0
  33. data/lib/action_view/helpers/tags.rb +41 -0
  34. data/lib/action_view/helpers/tags/base.rb +148 -0
  35. data/lib/action_view/helpers/tags/check_box.rb +64 -0
  36. data/lib/action_view/helpers/tags/checkable.rb +16 -0
  37. data/lib/action_view/helpers/tags/collection_check_boxes.rb +44 -0
  38. data/lib/action_view/helpers/tags/collection_helpers.rb +85 -0
  39. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +36 -0
  40. data/lib/action_view/helpers/tags/collection_select.rb +28 -0
  41. data/lib/action_view/helpers/tags/color_field.rb +25 -0
  42. data/lib/action_view/helpers/tags/date_field.rb +13 -0
  43. data/lib/action_view/helpers/tags/date_select.rb +72 -0
  44. data/lib/action_view/helpers/tags/datetime_field.rb +22 -0
  45. data/lib/action_view/helpers/tags/datetime_local_field.rb +19 -0
  46. data/lib/action_view/helpers/tags/datetime_select.rb +8 -0
  47. data/lib/action_view/helpers/tags/email_field.rb +8 -0
  48. data/lib/action_view/helpers/tags/file_field.rb +8 -0
  49. data/lib/action_view/helpers/tags/grouped_collection_select.rb +29 -0
  50. data/lib/action_view/helpers/tags/hidden_field.rb +8 -0
  51. data/lib/action_view/helpers/tags/label.rb +65 -0
  52. data/lib/action_view/helpers/tags/month_field.rb +13 -0
  53. data/lib/action_view/helpers/tags/number_field.rb +18 -0
  54. data/lib/action_view/helpers/tags/password_field.rb +12 -0
  55. data/lib/action_view/helpers/tags/radio_button.rb +31 -0
  56. data/lib/action_view/helpers/tags/range_field.rb +8 -0
  57. data/lib/action_view/helpers/tags/search_field.rb +24 -0
  58. data/lib/action_view/helpers/tags/select.rb +41 -0
  59. data/lib/action_view/helpers/tags/tel_field.rb +8 -0
  60. data/lib/action_view/helpers/tags/text_area.rb +18 -0
  61. data/lib/action_view/helpers/tags/text_field.rb +29 -0
  62. data/lib/action_view/helpers/tags/time_field.rb +13 -0
  63. data/lib/action_view/helpers/tags/time_select.rb +8 -0
  64. data/lib/action_view/helpers/tags/time_zone_select.rb +20 -0
  65. data/lib/action_view/helpers/tags/url_field.rb +8 -0
  66. data/lib/action_view/helpers/tags/week_field.rb +13 -0
  67. data/lib/action_view/helpers/text_helper.rb +447 -0
  68. data/lib/action_view/helpers/translation_helper.rb +111 -0
  69. data/lib/action_view/helpers/url_helper.rb +625 -0
  70. data/lib/action_view/layouts.rb +426 -0
  71. data/lib/action_view/locale/en.yml +56 -0
  72. data/lib/action_view/log_subscriber.rb +44 -0
  73. data/lib/action_view/lookup_context.rb +249 -0
  74. data/lib/action_view/model_naming.rb +12 -0
  75. data/lib/action_view/path_set.rb +77 -0
  76. data/lib/action_view/railtie.rb +49 -0
  77. data/lib/action_view/record_identifier.rb +84 -0
  78. data/lib/action_view/renderer/abstract_renderer.rb +47 -0
  79. data/lib/action_view/renderer/partial_renderer.rb +492 -0
  80. data/lib/action_view/renderer/renderer.rb +50 -0
  81. data/lib/action_view/renderer/streaming_template_renderer.rb +103 -0
  82. data/lib/action_view/renderer/template_renderer.rb +96 -0
  83. data/lib/action_view/rendering.rb +145 -0
  84. data/lib/action_view/routing_url_for.rb +109 -0
  85. data/lib/action_view/tasks/dependencies.rake +17 -0
  86. data/lib/action_view/template.rb +340 -0
  87. data/lib/action_view/template/error.rb +141 -0
  88. data/lib/action_view/template/handlers.rb +53 -0
  89. data/lib/action_view/template/handlers/builder.rb +26 -0
  90. data/lib/action_view/template/handlers/erb.rb +145 -0
  91. data/lib/action_view/template/handlers/raw.rb +11 -0
  92. data/lib/action_view/template/resolver.rb +329 -0
  93. data/lib/action_view/template/text.rb +34 -0
  94. data/lib/action_view/template/types.rb +57 -0
  95. data/lib/action_view/test_case.rb +272 -0
  96. data/lib/action_view/testing/resolvers.rb +50 -0
  97. data/lib/action_view/vendor/html-scanner.rb +20 -0
  98. data/lib/action_view/vendor/html-scanner/html/document.rb +68 -0
  99. data/lib/action_view/vendor/html-scanner/html/node.rb +532 -0
  100. data/lib/action_view/vendor/html-scanner/html/sanitizer.rb +188 -0
  101. data/lib/action_view/vendor/html-scanner/html/selector.rb +830 -0
  102. data/lib/action_view/vendor/html-scanner/html/tokenizer.rb +107 -0
  103. data/lib/action_view/vendor/html-scanner/html/version.rb +11 -0
  104. data/lib/action_view/version.rb +11 -0
  105. data/lib/action_view/view_paths.rb +96 -0
  106. 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