Skip to content
This repository
Browse code

Move rendering from AP to AV

  • Loading branch information...
commit 5759531a951ce495e2ac7dd8de79fa36ea798bac 1 parent e772b09
Łukasz Strzałkowski strzalek authored
1  actionpack/lib/abstract_controller.rb
@@ -13,7 +13,6 @@ module AbstractController
13 13 autoload :Helpers
14 14 autoload :Layouts
15 15 autoload :Logger
16   - autoload :Rendering
17 16 autoload :Translation
18 17 autoload :AssetPaths
19 18 autoload :UrlFor
423 actionpack/lib/abstract_controller/layouts.rb
... ... @@ -1,423 +0,0 @@
1   -require "active_support/core_ext/module/remove_method"
2   -
3   -module AbstractController
4   - # Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in
5   - # repeated setups. The inclusion pattern has pages that look like this:
6   - #
7   - # <%= render "shared/header" %>
8   - # Hello World
9   - # <%= render "shared/footer" %>
10   - #
11   - # This approach is a decent way of keeping common structures isolated from the changing content, but it's verbose
12   - # and if you ever want to change the structure of these two includes, you'll have to change all the templates.
13   - #
14   - # With layouts, you can flip it around and have the common structure know where to insert changing content. This means
15   - # that the header and footer are only mentioned in one place, like this:
16   - #
17   - # // The header part of this layout
18   - # <%= yield %>
19   - # // The footer part of this layout
20   - #
21   - # And then you have content pages that look like this:
22   - #
23   - # hello world
24   - #
25   - # At rendering time, the content page is computed and then inserted in the layout, like this:
26   - #
27   - # // The header part of this layout
28   - # hello world
29   - # // The footer part of this layout
30   - #
31   - # == Accessing shared variables
32   - #
33   - # Layouts have access to variables specified in the content pages and vice versa. This allows you to have layouts with
34   - # references that won't materialize before rendering time:
35   - #
36   - # <h1><%= @page_title %></h1>
37   - # <%= yield %>
38   - #
39   - # ...and content pages that fulfill these references _at_ rendering time:
40   - #
41   - # <% @page_title = "Welcome" %>
42   - # Off-world colonies offers you a chance to start a new life
43   - #
44   - # The result after rendering is:
45   - #
46   - # <h1>Welcome</h1>
47   - # Off-world colonies offers you a chance to start a new life
48   - #
49   - # == Layout assignment
50   - #
51   - # You can either specify a layout declaratively (using the #layout class method) or give
52   - # it the same name as your controller, and place it in <tt>app/views/layouts</tt>.
53   - # If a subclass does not have a layout specified, it inherits its layout using normal Ruby inheritance.
54   - #
55   - # For instance, if you have PostsController and a template named <tt>app/views/layouts/posts.html.erb</tt>,
56   - # that template will be used for all actions in PostsController and controllers inheriting
57   - # from PostsController.
58   - #
59   - # If you use a module, for instance Weblog::PostsController, you will need a template named
60   - # <tt>app/views/layouts/weblog/posts.html.erb</tt>.
61   - #
62   - # Since all your controllers inherit from ApplicationController, they will use
63   - # <tt>app/views/layouts/application.html.erb</tt> if no other layout is specified
64   - # or provided.
65   - #
66   - # == Inheritance Examples
67   - #
68   - # class BankController < ActionController::Base
69   - # # bank.html.erb exists
70   - #
71   - # class ExchangeController < BankController
72   - # # exchange.html.erb exists
73   - #
74   - # class CurrencyController < BankController
75   - #
76   - # class InformationController < BankController
77   - # layout "information"
78   - #
79   - # class TellerController < InformationController
80   - # # teller.html.erb exists
81   - #
82   - # class EmployeeController < InformationController
83   - # # employee.html.erb exists
84   - # layout nil
85   - #
86   - # class VaultController < BankController
87   - # layout :access_level_layout
88   - #
89   - # class TillController < BankController
90   - # layout false
91   - #
92   - # In these examples, we have three implicit lookup scenarios:
93   - # * The BankController uses the "bank" layout.
94   - # * The ExchangeController uses the "exchange" layout.
95   - # * The CurrencyController inherits the layout from BankController.
96   - #
97   - # However, when a layout is explicitly set, the explicitly set layout wins:
98   - # * The InformationController uses the "information" layout, explicitly set.
99   - # * The TellerController also uses the "information" layout, because the parent explicitly set it.
100   - # * The EmployeeController uses the "employee" layout, because it set the layout to nil, resetting the parent configuration.
101   - # * The VaultController chooses a layout dynamically by calling the <tt>access_level_layout</tt> method.
102   - # * The TillController does not use a layout at all.
103   - #
104   - # == Types of layouts
105   - #
106   - # Layouts are basically just regular templates, but the name of this template needs not be specified statically. Sometimes
107   - # you want to alternate layouts depending on runtime information, such as whether someone is logged in or not. This can
108   - # be done either by specifying a method reference as a symbol or using an inline method (as a proc).
109   - #
110   - # The method reference is the preferred approach to variable layouts and is used like this:
111   - #
112   - # class WeblogController < ActionController::Base
113   - # layout :writers_and_readers
114   - #
115   - # def index
116   - # # fetching posts
117   - # end
118   - #
119   - # private
120   - # def writers_and_readers
121   - # logged_in? ? "writer_layout" : "reader_layout"
122   - # end
123   - # end
124   - #
125   - # Now when a new request for the index action is processed, the layout will vary depending on whether the person accessing
126   - # is logged in or not.
127   - #
128   - # If you want to use an inline method, such as a proc, do something like this:
129   - #
130   - # class WeblogController < ActionController::Base
131   - # layout proc { |controller| controller.logged_in? ? "writer_layout" : "reader_layout" }
132   - # end
133   - #
134   - # If an argument isn't given to the proc, it's evaluated in the context of
135   - # the current controller anyway.
136   - #
137   - # class WeblogController < ActionController::Base
138   - # layout proc { logged_in? ? "writer_layout" : "reader_layout" }
139   - # end
140   - #
141   - # Of course, the most common way of specifying a layout is still just as a plain template name:
142   - #
143   - # class WeblogController < ActionController::Base
144   - # layout "weblog_standard"
145   - # end
146   - #
147   - # The template will be looked always in <tt>app/views/layouts/</tt> folder. But you can point
148   - # <tt>layouts</tt> folder direct also. <tt>layout "layouts/demo"</tt> is the same as <tt>layout "demo"</tt>.
149   - #
150   - # Setting the layout to nil forces it to be looked up in the filesystem and fallbacks to the parent behavior if none exists.
151   - # Setting it to nil is useful to re-enable template lookup overriding a previous configuration set in the parent:
152   - #
153   - # class ApplicationController < ActionController::Base
154   - # layout "application"
155   - # end
156   - #
157   - # class PostsController < ApplicationController
158   - # # Will use "application" layout
159   - # end
160   - #
161   - # class CommentsController < ApplicationController
162   - # # Will search for "comments" layout and fallback "application" layout
163   - # layout nil
164   - # end
165   - #
166   - # == Conditional layouts
167   - #
168   - # If you have a layout that by default is applied to all the actions of a controller, you still have the option of rendering
169   - # a given action or set of actions without a layout, or restricting a layout to only a single action or a set of actions. The
170   - # <tt>:only</tt> and <tt>:except</tt> options can be passed to the layout call. For example:
171   - #
172   - # class WeblogController < ActionController::Base
173   - # layout "weblog_standard", except: :rss
174   - #
175   - # # ...
176   - #
177   - # end
178   - #
179   - # This will assign "weblog_standard" as the WeblogController's layout for all actions except for the +rss+ action, which will
180   - # be rendered directly, without wrapping a layout around the rendered view.
181   - #
182   - # Both the <tt>:only</tt> and <tt>:except</tt> condition can accept an arbitrary number of method references, so
183   - # #<tt>except: [ :rss, :text_only ]</tt> is valid, as is <tt>except: :rss</tt>.
184   - #
185   - # == Using a different layout in the action render call
186   - #
187   - # If most of your actions use the same layout, it makes perfect sense to define a controller-wide layout as described above.
188   - # Sometimes you'll have exceptions where one action wants to use a different layout than the rest of the controller.
189   - # You can do this by passing a <tt>:layout</tt> option to the <tt>render</tt> call. For example:
190   - #
191   - # class WeblogController < ActionController::Base
192   - # layout "weblog_standard"
193   - #
194   - # def help
195   - # render action: "help", layout: "help"
196   - # end
197   - # end
198   - #
199   - # This will override the controller-wide "weblog_standard" layout, and will render the help action with the "help" layout instead.
200   - module Layouts
201   - extend ActiveSupport::Concern
202   -
203   - include Rendering
204   -
205   - included do
206   - class_attribute :_layout, :_layout_conditions, :instance_accessor => false
207   - self._layout = nil
208   - self._layout_conditions = {}
209   - _write_layout_method
210   - end
211   -
212   - delegate :_layout_conditions, to: :class
213   -
214   - module ClassMethods
215   - def inherited(klass) # :nodoc:
216   - super
217   - klass._write_layout_method
218   - end
219   -
220   - # This module is mixed in if layout conditions are provided. This means
221   - # that if no layout conditions are used, this method is not used
222   - module LayoutConditions # :nodoc:
223   - private
224   -
225   - # Determines whether the current action has a layout definition by
226   - # checking the action name against the :only and :except conditions
227   - # set by the <tt>layout</tt> method.
228   - #
229   - # ==== Returns
230   - # * <tt> Boolean</tt> - True if the action has a layout definition, false otherwise.
231   - def _conditional_layout?
232   - return unless super
233   -
234   - conditions = _layout_conditions
235   -
236   - if only = conditions[:only]
237   - only.include?(action_name)
238   - elsif except = conditions[:except]
239   - !except.include?(action_name)
240   - else
241   - true
242   - end
243   - end
244   - end
245   -
246   - # Specify the layout to use for this class.
247   - #
248   - # If the specified layout is a:
249   - # String:: the String is the template name
250   - # Symbol:: call the method specified by the symbol, which will return the template name
251   - # false:: There is no layout
252   - # true:: raise an ArgumentError
253   - # nil:: Force default layout behavior with inheritance
254   - #
255   - # ==== Parameters
256   - # * <tt>layout</tt> - The layout to use.
257   - #
258   - # ==== Options (conditions)
259   - # * :only - A list of actions to apply this layout to.
260   - # * :except - Apply this layout to all actions but this one.
261   - def layout(layout, conditions = {})
262   - include LayoutConditions unless conditions.empty?
263   -
264   - conditions.each {|k, v| conditions[k] = Array(v).map {|a| a.to_s} }
265   - self._layout_conditions = conditions
266   -
267   - self._layout = layout
268   - _write_layout_method
269   - end
270   -
271   - # If no layout is supplied, look for a template named the return
272   - # value of this method.
273   - #
274   - # ==== Returns
275   - # * <tt>String</tt> - A template name
276   - def _implied_layout_name # :nodoc:
277   - controller_path
278   - end
279   -
280   - # Creates a _layout method to be called by _default_layout .
281   - #
282   - # If a layout is not explicitly mentioned then look for a layout with the controller's name.
283   - # if nothing is found then try same procedure to find super class's layout.
284   - def _write_layout_method # :nodoc:
285   - remove_possible_method(:_layout)
286   -
287   - prefixes = _implied_layout_name =~ /\blayouts/ ? [] : ["layouts"]
288   - default_behavior = "lookup_context.find_all('#{_implied_layout_name}', #{prefixes.inspect}).first || super"
289   - name_clause = if name
290   - default_behavior
291   - else
292   - <<-RUBY
293   - super
294   - RUBY
295   - end
296   -
297   - layout_definition = case _layout
298   - when String
299   - _layout.inspect
300   - when Symbol
301   - <<-RUBY
302   - #{_layout}.tap do |layout|
303   - return #{default_behavior} if layout.nil?
304   - unless layout.is_a?(String) || !layout
305   - raise ArgumentError, "Your layout method :#{_layout} returned \#{layout}. It " \
306   - "should have returned a String, false, or nil"
307   - end
308   - end
309   - RUBY
310   - when Proc
311   - define_method :_layout_from_proc, &_layout
312   - protected :_layout_from_proc
313   - <<-RUBY
314   - result = _layout_from_proc(#{_layout.arity == 0 ? '' : 'self'})
315   - return #{default_behavior} if result.nil?
316   - result
317   - RUBY
318   - when false
319   - nil
320   - when true
321   - raise ArgumentError, "Layouts must be specified as a String, Symbol, Proc, false, or nil"
322   - when nil
323   - name_clause
324   - end
325   -
326   - self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
327   - def _layout
328   - if _conditional_layout?
329   - #{layout_definition}
330   - else
331   - #{name_clause}
332   - end
333   - end
334   - private :_layout
335   - RUBY
336   - end
337   - end
338   -
339   - def _normalize_options(options) # :nodoc:
340   - super
341   -
342   - if _include_layout?(options)
343   - layout = options.delete(:layout) { :default }
344   - options[:layout] = _layout_for_option(layout)
345   - end
346   - end
347   -
348   - attr_internal_writer :action_has_layout
349   -
350   - def initialize(*) # :nodoc:
351   - @_action_has_layout = true
352   - super
353   - end
354   -
355   - # Controls whether an action should be rendered using a layout.
356   - # If you want to disable any <tt>layout</tt> settings for the
357   - # current action so that it is rendered without a layout then
358   - # either override this method in your controller to return false
359   - # for that action or set the <tt>action_has_layout</tt> attribute
360   - # to false before rendering.
361   - def action_has_layout?
362   - @_action_has_layout
363   - end
364   -
365   - private
366   -
367   - def _conditional_layout?
368   - true
369   - end
370   -
371   - # This will be overwritten by _write_layout_method
372   - def _layout; end
373   -
374   - # Determine the layout for a given name, taking into account the name type.
375   - #
376   - # ==== Parameters
377   - # * <tt>name</tt> - The name of the template
378   - def _layout_for_option(name)
379   - case name
380   - when String then _normalize_layout(name)
381   - when Proc then name
382   - when true then Proc.new { _default_layout(true) }
383   - when :default then Proc.new { _default_layout(false) }
384   - when false, nil then nil
385   - else
386   - raise ArgumentError,
387   - "String, Proc, :default, true, or false, expected for `layout'; you passed #{name.inspect}"
388   - end
389   - end
390   -
391   - def _normalize_layout(value)
392   - value.is_a?(String) && value !~ /\blayouts/ ? "layouts/#{value}" : value
393   - end
394   -
395   - # Returns the default layout for this controller.
396   - # Optionally raises an exception if the layout could not be found.
397   - #
398   - # ==== Parameters
399   - # * <tt>require_layout</tt> - If set to true and layout is not found,
400   - # an ArgumentError exception is raised (defaults to false)
401   - #
402   - # ==== Returns
403   - # * <tt>template</tt> - The template object for the default layout (or nil)
404   - def _default_layout(require_layout = false)
405   - begin
406   - value = _layout if action_has_layout?
407   - rescue NameError => e
408   - raise e, "Could not render layout: #{e.message}"
409   - end
410   -
411   - if require_layout && action_has_layout? && !value
412   - raise ArgumentError,
413   - "There was no default layout for #{self.class} in #{view_paths.inspect}"
414   - end
415   -
416   - _normalize_layout(value)
417   - end
418   -
419   - def _include_layout?(options)
420   - (options.keys & [:text, :inline, :partial]).empty? || options.key?(:layout)
421   - end
422   - end
423   -end
187 actionpack/lib/abstract_controller/rendering.rb
... ... @@ -1,6 +1,3 @@
1   -require "abstract_controller/base"
2   -require "action_view"
3   -
4 1 module AbstractController
5 2 class DoubleRenderError < Error
6 3 DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"."
@@ -9,188 +6,4 @@ def initialize(message = nil)
9 6 super(message || DEFAULT_MESSAGE)
10 7 end
11 8 end
12   -
13   - # This is a class to fix I18n global state. Whenever you provide I18n.locale during a request,
14   - # it will trigger the lookup_context and consequently expire the cache.
15   - class I18nProxy < ::I18n::Config #:nodoc:
16   - attr_reader :original_config, :lookup_context
17   -
18   - def initialize(original_config, lookup_context)
19   - original_config = original_config.original_config if original_config.respond_to?(:original_config)
20   - @original_config, @lookup_context = original_config, lookup_context
21   - end
22   -
23   - def locale
24   - @original_config.locale
25   - end
26   -
27   - def locale=(value)
28   - @lookup_context.locale = value
29   - end
30   - end
31   -
32   - module Rendering
33   - extend ActiveSupport::Concern
34   - include AbstractController::ViewPaths
35   -
36   - included do
37   - class_attribute :protected_instance_variables
38   - self.protected_instance_variables = []
39   - end
40   -
41   - # Overwrite process to setup I18n proxy.
42   - def process(*) #:nodoc:
43   - old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context)
44   - super
45   - ensure
46   - I18n.config = old_config
47   - end
48   -
49   - module ClassMethods
50   - def view_context_class
51   - @view_context_class ||= begin
52   - routes = respond_to?(:_routes) && _routes
53   - helpers = respond_to?(:_helpers) && _helpers
54   -
55   - Class.new(ActionView::Base) do
56   - if routes
57   - include routes.url_helpers
58   - include routes.mounted_helpers
59   - end
60   -
61   - if helpers
62   - include helpers
63   - end
64   - end
65   - end
66   - end
67   - end
68   -
69   - attr_internal_writer :view_context_class
70   -
71   - def view_context_class
72   - @_view_context_class ||= self.class.view_context_class
73   - end
74   -
75   - # An instance of a view class. The default view class is ActionView::Base
76   - #
77   - # The view class must have the following methods:
78   - # View.new[lookup_context, assigns, controller]
79   - # Create a new ActionView instance for a controller
80   - # View#render[options]
81   - # Returns String with the rendered template
82   - #
83   - # Override this method in a module to change the default behavior.
84   - def view_context
85   - view_context_class.new(view_renderer, view_assigns, self)
86   - end
87   -
88   - # Returns an object that is able to render templates.
89   - def view_renderer
90   - @_view_renderer ||= ActionView::Renderer.new(lookup_context)
91   - end
92   -
93   - # Normalize arguments, options and then delegates render_to_body and
94   - # sticks the result in self.response_body.
95   - def render(*args, &block)
96   - options = _normalize_render(*args, &block)
97   - self.response_body = render_to_body(options)
98   - end
99   -
100   - # Raw rendering of a template to a string.
101   - #
102   - # It is similar to render, except that it does not
103   - # set the response_body and it should be guaranteed
104   - # to always return a string.
105   - #
106   - # If a component extends the semantics of response_body
107   - # (as Action Controller extends it to be anything that
108   - # responds to the method each), this method needs to be
109   - # overridden in order to still return a string.
110   - # :api: plugin
111   - def render_to_string(*args, &block)
112   - options = _normalize_render(*args, &block)
113   - render_to_body(options)
114   - end
115   -
116   - # Raw rendering of a template.
117   - # :api: plugin
118   - def render_to_body(options = {})
119   - _process_options(options)
120   - _render_template(options)
121   - end
122   -
123   - # Find and renders a template based on the options given.
124   - # :api: private
125   - def _render_template(options) #:nodoc:
126   - lookup_context.rendered_format = nil if options[:formats]
127   - view_renderer.render(view_context, options)
128   - end
129   -
130   - DEFAULT_PROTECTED_INSTANCE_VARIABLES = [
131   - :@_action_name, :@_response_body, :@_formats, :@_prefixes, :@_config,
132   - :@_view_context_class, :@_view_renderer, :@_lookup_context
133   - ]
134   -
135   - # This method should return a hash with assigns.
136   - # You can overwrite this configuration per controller.
137   - # :api: public
138   - def view_assigns
139   - hash = {}
140   - variables = instance_variables
141   - variables -= protected_instance_variables
142   - variables -= DEFAULT_PROTECTED_INSTANCE_VARIABLES
143   - variables.each { |name| hash[name[1..-1]] = instance_variable_get(name) }
144   - hash
145   - end
146   -
147   - private
148   -
149   - # Normalize args and options.
150   - # :api: private
151   - def _normalize_render(*args, &block)
152   - options = _normalize_args(*args, &block)
153   - _normalize_options(options)
154   - options
155   - end
156   -
157   - # Normalize args by converting render "foo" to render :action => "foo" and
158   - # render "foo/bar" to render :file => "foo/bar".
159   - # :api: plugin
160   - def _normalize_args(action=nil, options={})
161   - case action
162   - when NilClass
163   - when Hash
164   - options = action
165   - when String, Symbol
166   - action = action.to_s
167   - key = action.include?(?/) ? :file : :action
168   - options[key] = action
169   - else
170   - options[:partial] = action
171   - end
172   -
173   - options
174   - end
175   -
176   - # Normalize options.
177   - # :api: plugin
178   - def _normalize_options(options)
179   - if options[:partial] == true
180   - options[:partial] = action_name
181   - end
182   -
183   - if (options.keys & [:partial, :file, :template]).empty?
184   - options[:prefixes] ||= _prefixes
185   - end
186   -
187   - options[:template] ||= (options[:action] || action_name).to_s
188   - options
189   - end
190   -
191   - # Process extra options.
192   - # :api: plugin
193   - def _process_options(options)
194   - end
195   - end
196 9 end
2  actionpack/lib/action_controller/metal/rendering.rb
@@ -2,7 +2,7 @@ module ActionController
2 2 module Rendering
3 3 extend ActiveSupport::Concern
4 4
5   - include AbstractController::Rendering
  5 + include ActionView::Rendering
6 6
7 7 # Before processing, set the request formats in current controller formats.
8 8 def process_action(*) #:nodoc:
2  actionpack/lib/action_controller/metal/streaming.rb
@@ -193,7 +193,7 @@ module ActionController #:nodoc:
193 193 module Streaming
194 194 extend ActiveSupport::Concern
195 195
196   - include AbstractController::Rendering
  196 + include ActionView::Rendering
197 197
198 198 protected
199 199
1  actionview/lib/action_view.rb
@@ -36,6 +36,7 @@ module ActionView
36 36 autoload :LookupContext
37 37 autoload :PathSet
38 38 autoload :RecordIdentifier
  39 + autoload :Rendering
39 40 autoload :RoutingUrlFor
40 41 autoload :Template
41 42 autoload :ViewPaths
186 actionview/lib/action_view/rendering.rb
... ... @@ -0,0 +1,186 @@
  1 +
  2 +module ActionView
  3 + # This is a class to fix I18n global state. Whenever you provide I18n.locale during a request,
  4 + # it will trigger the lookup_context and consequently expire the cache.
  5 + class I18nProxy < ::I18n::Config #:nodoc:
  6 + attr_reader :original_config, :lookup_context
  7 +
  8 + def initialize(original_config, lookup_context)
  9 + original_config = original_config.original_config if original_config.respond_to?(:original_config)
  10 + @original_config, @lookup_context = original_config, lookup_context
  11 + end
  12 +
  13 + def locale
  14 + @original_config.locale
  15 + end
  16 +
  17 + def locale=(value)
  18 + @lookup_context.locale = value
  19 + end
  20 + end
  21 +
  22 + module Rendering
  23 + extend ActiveSupport::Concern
  24 + include ActionView::ViewPaths
  25 +
  26 + included do
  27 + class_attribute :protected_instance_variables
  28 + self.protected_instance_variables = []
  29 + end
  30 +
  31 + # Overwrite process to setup I18n proxy.
  32 + def process(*) #:nodoc:
  33 + old_config, I18n.config = I18n.config, I18nProxy.new(I18n.config, lookup_context)
  34 + super
  35 + ensure
  36 + I18n.config = old_config
  37 + end
  38 +
  39 + module ClassMethods
  40 + def view_context_class
  41 + @view_context_class ||= begin
  42 + routes = respond_to?(:_routes) && _routes
  43 + helpers = respond_to?(:_helpers) && _helpers
  44 +
  45 + Class.new(ActionView::Base) do
  46 + if routes
  47 + include routes.url_helpers
  48 + include routes.mounted_helpers
  49 + end
  50 +
  51 + if helpers
  52 + include helpers
  53 + end
  54 + end
  55 + end
  56 + end
  57 + end
  58 +
  59 + attr_internal_writer :view_context_class
  60 +
  61 + def view_context_class
  62 + @_view_context_class ||= self.class.view_context_class
  63 + end
  64 +
  65 + # An instance of a view class. The default view class is ActionView::Base
  66 + #
  67 + # The view class must have the following methods:
  68 + # View.new[lookup_context, assigns, controller]
  69 + # Create a new ActionView instance for a controller
  70 + # View#render[options]
  71 + # Returns String with the rendered template
  72 + #
  73 + # Override this method in a module to change the default behavior.
  74 + def view_context
  75 + view_context_class.new(view_renderer, view_assigns, self)
  76 + end
  77 +
  78 + # Returns an object that is able to render templates.
  79 + def view_renderer
  80 + @_view_renderer ||= ActionView::Renderer.new(lookup_context)
  81 + end
  82 +
  83 + # Normalize arguments, options and then delegates render_to_body and
  84 + # sticks the result in self.response_body.
  85 + def render(*args, &block)
  86 + options = _normalize_render(*args, &block)
  87 + self.response_body = render_to_body(options)
  88 + end
  89 +
  90 + # Raw rendering of a template to a string.
  91 + #
  92 + # It is similar to render, except that it does not
  93 + # set the response_body and it should be guaranteed
  94 + # to always return a string.
  95 + #
  96 + # If a component extends the semantics of response_body
  97 + # (as Action Controller extends it to be anything that
  98 + # responds to the method each), this method needs to be
  99 + # overridden in order to still return a string.
  100 + # :api: plugin
  101 + def render_to_string(*args, &block)
  102 + options = _normalize_render(*args, &block)
  103 + render_to_body(options)
  104 + end
  105 +
  106 + # Raw rendering of a template.
  107 + # :api: plugin
  108 + def render_to_body(options = {})
  109 + _process_options(options)
  110 + _render_template(options)
  111 + end
  112 +
  113 + # Find and renders a template based on the options given.
  114 + # :api: private
  115 + def _render_template(options) #:nodoc:
  116 + lookup_context.rendered_format = nil if options[:formats]
  117 + view_renderer.render(view_context, options)
  118 + end
  119 +
  120 + DEFAULT_PROTECTED_INSTANCE_VARIABLES = [
  121 + :@_action_name, :@_response_body, :@_formats, :@_prefixes, :@_config,
  122 + :@_view_context_class, :@_view_renderer, :@_lookup_context
  123 + ]
  124 +
  125 + # This method should return a hash with assigns.
  126 + # You can overwrite this configuration per controller.
  127 + # :api: public
  128 + def view_assigns
  129 + hash = {}
  130 + variables = instance_variables
  131 + variables -= protected_instance_variables
  132 + variables -= DEFAULT_PROTECTED_INSTANCE_VARIABLES
  133 + variables.each { |name| hash[name[1..-1]] = instance_variable_get(name) }
  134 + hash
  135 + end
  136 +
  137 + private
  138 +
  139 + # Normalize args and options.
  140 + # :api: private
  141 + def _normalize_render(*args, &block)
  142 + options = _normalize_args(*args, &block)
  143 + _normalize_options(options)
  144 + options
  145 + end
  146 +
  147 + # Normalize args by converting render "foo" to render :action => "foo" and
  148 + # render "foo/bar" to render :file => "foo/bar".
  149 + # :api: plugin
  150 + def _normalize_args(action=nil, options={})
  151 + case action
  152 + when NilClass
  153 + when Hash
  154 + options = action
  155 + when String, Symbol
  156 + action = action.to_s
  157 + key = action.include?(?/) ? :file : :action
  158 + options[key] = action
  159 + else
  160 + options[:partial] = action
  161 + end
  162 +
  163 + options
  164 + end
  165 +
  166 + # Normalize options.
  167 + # :api: plugin
  168 + def _normalize_options(options)
  169 + if options[:partial] == true
  170 + options[:partial] = action_name
  171 + end
  172 +
  173 + if (options.keys & [:partial, :file, :template]).empty?
  174 + options[:prefixes] ||= _prefixes
  175 + end
  176 +
  177 + options[:template] ||= (options[:action] || action_name).to_s
  178 + options
  179 + end
  180 +
  181 + # Process extra options.
  182 + # :api: plugin
  183 + def _process_options(options)
  184 + end
  185 + end
  186 +end

0 comments on commit 5759531

Please sign in to comment.
Something went wrong with that request. Please try again.