From f2c0a353aef41a6df2de8e1fe3eaa3d8bbd8a6dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 12 Mar 2010 20:39:53 +0100 Subject: Finish cleaning up rendering stack from views and move assigns evaluation to controller (so plugins and/or controllers can overwrite just one method). --- actionpack/lib/abstract_controller.rb | 1 + actionpack/lib/abstract_controller/assigns.rb | 21 ++++++++++++ actionpack/lib/abstract_controller/layouts.rb | 6 ++++ actionpack/lib/abstract_controller/rendering.rb | 16 +++++----- .../lib/action_controller/metal/mime_responds.rb | 1 + .../lib/action_controller/metal/renderers.rb | 3 +- .../lib/action_controller/metal/rendering.rb | 21 ++++++------ actionpack/lib/action_view/base.rb | 9 ------ .../lib/action_view/helpers/prototype_helper.rb | 1 - actionpack/lib/action_view/render/layouts.rb | 5 +-- actionpack/lib/action_view/render/rendering.rb | 37 +++++----------------- .../lib/action_view/template/handlers/rjs.rb | 3 +- actionpack/lib/action_view/template/text.rb | 14 ++++---- 13 files changed, 66 insertions(+), 72 deletions(-) create mode 100644 actionpack/lib/abstract_controller/assigns.rb (limited to 'actionpack/lib') diff --git a/actionpack/lib/abstract_controller.rb b/actionpack/lib/abstract_controller.rb index 2da4dc052c..de95f935c2 100644 --- a/actionpack/lib/abstract_controller.rb +++ b/actionpack/lib/abstract_controller.rb @@ -12,6 +12,7 @@ require 'active_support/i18n' module AbstractController extend ActiveSupport::Autoload + autoload :Assigns autoload :Base autoload :Callbacks autoload :Collector diff --git a/actionpack/lib/abstract_controller/assigns.rb b/actionpack/lib/abstract_controller/assigns.rb new file mode 100644 index 0000000000..21459c6d51 --- /dev/null +++ b/actionpack/lib/abstract_controller/assigns.rb @@ -0,0 +1,21 @@ +module AbstractController + module Assigns + # This method should return a hash with assigns. + # You can overwrite this configuration per controller. + # :api: public + def view_assigns + hash = {} + variables = instance_variable_names + variables -= protected_instance_variables if respond_to?(:protected_instance_variables) + variables.each { |name| hash[name] = instance_variable_get(name) } + hash + end + + # This method assigns the hash specified in _assigns_hash to the given object. + # :api: private + # TODO Ideally, this should be done on AV::Base.new initialization. + def _evaluate_assigns(object) + view_assigns.each { |k,v| object.instance_variable_set(k, v) } + end + end +end \ No newline at end of file diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index 2f9616124a..95a6101109 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -284,6 +284,12 @@ module AbstractController layout = options.key?(:layout) ? options.delete(:layout) : :default value = _layout_for_option(layout) options[:layout] = (value =~ /\blayouts/ ? value : "layouts/#{value}") if value + + # TODO Layout for partials should be handled here, because inside the + # partial renderer it looks for the layout as a partial. + if options.key?(:partial) && options[:layout] + options[:layout] = view_context.find_layout(options[:layout]) + end end end diff --git a/actionpack/lib/abstract_controller/rendering.rb b/actionpack/lib/abstract_controller/rendering.rb index 42f4939108..16664098e5 100644 --- a/actionpack/lib/abstract_controller/rendering.rb +++ b/actionpack/lib/abstract_controller/rendering.rb @@ -31,6 +31,8 @@ module AbstractController module Rendering extend ActiveSupport::Concern + + include AbstractController::Assigns include AbstractController::ViewPaths # Overwrite process to setup I18n proxy. @@ -54,8 +56,8 @@ module AbstractController @_view_context ||= ActionView::Base.for_controller(self) end - # Mostly abstracts the fact that calling render twice is a DoubleRenderError. - # Delegates render_to_body and sticks the result in self.response_body. + # Normalize arguments, options and then delegates render_to_body and + # sticks the result in self.response_body. def render(*args, &block) options = _normalize_args(*args, &block) _normalize_options(options) @@ -78,8 +80,10 @@ module AbstractController end # Find and renders a template based on the options given. - def _render_template(options) - view_context.render_template(options) { |template| _with_template_hook(template) } + # :api: private + def _render_template(options) #:nodoc: + _evaluate_assigns(view_context) + view_context.render(options) end # The prefix used in render "foo" shortcuts. @@ -134,9 +138,5 @@ module AbstractController def _process_options(options) end - - def _with_template_hook(template) - self.formats = template.formats - end end end diff --git a/actionpack/lib/action_controller/metal/mime_responds.rb b/actionpack/lib/action_controller/metal/mime_responds.rb index e70a20b2be..2ac199265d 100644 --- a/actionpack/lib/action_controller/metal/mime_responds.rb +++ b/actionpack/lib/action_controller/metal/mime_responds.rb @@ -261,6 +261,7 @@ module ActionController #:nodoc: block.call(collector) if block_given? if format = request.negotiate_mime(collector.order) + self.content_type ||= format.to_s self.formats = [format.to_sym] collector.response_for(format) else diff --git a/actionpack/lib/action_controller/metal/renderers.rb b/actionpack/lib/action_controller/metal/renderers.rb index 49d3d6b466..08325b468c 100644 --- a/actionpack/lib/action_controller/metal/renderers.rb +++ b/actionpack/lib/action_controller/metal/renderers.rb @@ -87,8 +87,9 @@ module ActionController end add :update do |proc, options| + _evaluate_assigns(view_context) generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(view_context, &proc) - self.content_type = Mime::JS + self.content_type = Mime::JS self.response_body = generator.to_s end end diff --git a/actionpack/lib/action_controller/metal/rendering.rb b/actionpack/lib/action_controller/metal/rendering.rb index f892bd9b91..2167fe9a32 100644 --- a/actionpack/lib/action_controller/metal/rendering.rb +++ b/actionpack/lib/action_controller/metal/rendering.rb @@ -5,26 +5,31 @@ module ActionController include ActionController::RackDelegation include AbstractController::Rendering - def process(*) + # Before processing, set the request formats in current controller formats. + def process(*) #:nodoc: self.formats = request.formats.map { |x| x.to_sym } super end - def render(*args) + # Check for double render errors and set the content_type after rendering. + def render(*args) #:nodoc: raise ::AbstractController::DoubleRenderError if response_body super + self.content_type ||= Mime[formats.first].to_s response_body end private - def _normalize_args(action=nil, options={}, &blk) + # Normalize arguments by catching blocks and setting them on :update. + def _normalize_args(action=nil, options={}, &blk) #:nodoc: options = super options[:update] = blk if block_given? options end - def _normalize_options(options) + # Normalize both text and status options. + def _normalize_options(options) #:nodoc: if options.key?(:text) && options[:text].respond_to?(:to_text) options[:text] = options[:text].to_text end @@ -36,7 +41,8 @@ module ActionController super end - def _process_options(options) + # Process controller specific options, as status, content-type and location. + def _process_options(options) #:nodoc: status, content_type, location = options.values_at(:status, :content_type, :location) self.status = status if status @@ -46,10 +52,5 @@ module ActionController super end - def _with_template_hook(template) - super - self.content_type ||= template.mime_type.to_s - end - end end diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index f1b1c22075..feaf45c333 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -264,14 +264,5 @@ module ActionView #:nodoc: response.body_parts << part nil end - - # Evaluates the local assigns and controller ivars, pushes them to the view. - def _evaluate_assigns_and_ivars #:nodoc: - if controller - variables = controller.instance_variable_names - variables -= controller.protected_instance_variables if controller.respond_to?(:protected_instance_variables) - variables.each { |name| instance_variable_set(name, controller.instance_variable_get(name)) } - end - end end end diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index be49b5cc28..e58fdf81fb 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -180,7 +180,6 @@ module ActionView # #include_helpers_from_context has nothing to overwrite. class JavaScriptGenerator #:nodoc: def initialize(context, &block) #:nodoc: - context._evaluate_assigns_and_ivars @context, @lines = context, [] @context.update_details(:formats => [:js, :html]) do include_helpers_from_context diff --git a/actionpack/lib/action_view/render/layouts.rb b/actionpack/lib/action_view/render/layouts.rb index 91a92a833a..0cb688ca77 100644 --- a/actionpack/lib/action_view/render/layouts.rb +++ b/actionpack/lib/action_view/render/layouts.rb @@ -1,8 +1,5 @@ -require 'active_support/core_ext/object/try' - module ActionView module Layouts - # You can think of a layout as a method that is called with a block. _layout_for # returns the contents that are yielded to the layout. If the user calls yield # :some_name, the block, by default, returns content_for(:some_name). If the user @@ -46,7 +43,7 @@ module ActionView # This is the method which actually finds the layout using details in the lookup # context object. If no layout is found, it checkes if at least a layout with # the given name exists across all details before raising the error. - def _find_layout(layout) #:nodoc: + def find_layout(layout) #:nodoc: begin layout =~ /^\// ? with_fallbacks { find_template(layout) } : find_template(layout) diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index d9ac1f6290..9b5b976727 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -12,14 +12,17 @@ module ActionView # # If no options hash is passed or :update specified, the default is to render a partial and use the second parameter # as the locals hash. - def render(options = {}, locals = {}, &block) #:nodoc: + def render(options = {}, locals = {}, &block) case options when Hash if block_given? content = _render_partial(options.merge(:partial => options[:layout]), &block) safe_concat(content) + elsif options.key?(:partial) + _render_partial(options) else - _render(options) + template = _determine_template(options) + _render_template(template, options[:layout], options) end when :update update_page(&block) @@ -28,31 +31,6 @@ module ActionView end end - # This is the API to render a ViewContext's template from a controller. - def render_template(options, &block) - _evaluate_assigns_and_ivars - - # TODO Layout for partials should be handled here, because inside the - # partial renderer it looks for the layout as a partial. - if options.key?(:partial) && options[:layout] - options[:layout] = _find_layout(options[:layout]) - end - - _render(options, &block) - end - - # This method holds the common render logic for both controllers and - # views rendering stacks. - def _render(options) #:nodoc: - if options.key?(:partial) - _render_partial(options) - else - template = _determine_template(options) - yield template if block_given? - _render_template(template, options[:layout], options) - end - end - # Determine the template to be rendered using the given options. def _determine_template(options) #:nodoc: if options.key?(:inline) @@ -71,8 +49,10 @@ module ActionView # Renders the given template. An string representing the layout can be # supplied as well. def _render_template(template, layout = nil, options = {}) #:nodoc: + self.formats = template.formats + locals = options[:locals] || {} - layout = _find_layout(layout) if layout + layout = find_layout(layout) if layout ActiveSupport::Notifications.instrument("action_view.render_template", :identifier => template.identifier, :layout => layout.try(:identifier)) do @@ -88,6 +68,5 @@ module ActionView content end end - end end diff --git a/actionpack/lib/action_view/template/handlers/rjs.rb b/actionpack/lib/action_view/template/handlers/rjs.rb index 63e7dc0902..128be5077c 100644 --- a/actionpack/lib/action_view/template/handlers/rjs.rb +++ b/actionpack/lib/action_view/template/handlers/rjs.rb @@ -6,8 +6,7 @@ module ActionView self.default_format = Mime::JS def compile(template) - "controller.response.content_type ||= Mime::JS;" + - "update_page do |page|;#{template.source}\nend" + "update_page do |page|;#{template.source}\nend" end def default_format diff --git a/actionpack/lib/action_view/template/text.rb b/actionpack/lib/action_view/template/text.rb index df394b0fb0..269340514c 100644 --- a/actionpack/lib/action_view/template/text.rb +++ b/actionpack/lib/action_view/template/text.rb @@ -1,10 +1,12 @@ module ActionView #:nodoc: class Template class Text < String #:nodoc: - def initialize(string, content_type = nil) + attr_accessor :mime_type + + def initialize(string, mime_type = nil) super(string.to_s) - @content_type = Mime[content_type] || content_type if content_type - @content_type ||= Mime::TEXT + @mime_type = Mime[mime_type] || mime_type if mime_type + @mime_type ||= Mime::TEXT end def identifier @@ -19,12 +21,8 @@ module ActionView #:nodoc: to_s end - def mime_type - @content_type - end - def formats - [@content_type.to_sym] + [@mime_type.to_sym] end def partial? -- cgit v1.2.3