From e90bbbdd837ffc83dccbd05528c4f1521e3956ee Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 12 Feb 2006 01:06:45 +0000 Subject: Add caution and restyle components git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3577 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- actionpack/lib/action_controller/components.rb | 105 ++++++++++++++----------- 1 file changed, 58 insertions(+), 47 deletions(-) (limited to 'actionpack/lib/action_controller/components.rb') diff --git a/actionpack/lib/action_controller/components.rb b/actionpack/lib/action_controller/components.rb index ba08670610..89a2c03aea 100644 --- a/actionpack/lib/action_controller/components.rb +++ b/actionpack/lib/action_controller/components.rb @@ -1,18 +1,18 @@ module ActionController #:nodoc: - # Components allows you to call other actions for their rendered response while executing another action. You can either delegate + # Components allow you to call other actions for their rendered response while executing another action. You can either delegate # the entire response rendering or you can mix a partial response in with your other content. # # class WeblogController < ActionController::Base # # Performs a method and then lets hello_world output its render # def delegate_action # do_other_stuff_before_hello_world - # render_component :controller => "greeter", :action => "hello_world", :params => { "person" => "david" } + # render_component :controller => "greeter", :action => "hello_world", :params => { :person => "david" } # end # end # # class GreeterController < ActionController::Base # def hello_world - # render_text "#{@params['person']} says, Hello World!" + # render :text => "#{params[:person]} says, Hello World!" # end # end # @@ -22,11 +22,18 @@ module ActionController #:nodoc: # <%= render_component :controller => "greeter", :action => "hello_world" %> # # It is also possible to specify the controller as a class constant, bypassing the inflector - # code to compute the controller class at runtime. Therefore, + # code to compute the controller class at runtime: # # <%= render_component :controller => GreeterController, :action => "hello_world" %> - # - # would work as well and be slightly faster. + # + # == When to use components + # + # Components should be used with care. They're significantly slower than simply splitting reusable parts into partials and + # conceptually more complicated. Don't use components as a way of separating concerns inside a single application. Instead, + # reserve components to those rare cases where you truly have reusable view and controller elements that can be employed + # across many applications at once. + # + # So to repeat: Components are a special-purpose approach that can often be replaced with better use of partials and filters. module Components def self.included(base) #:nodoc: base.extend(ClassMethods) @@ -51,6 +58,7 @@ module ActionController #:nodoc: def uses_component_template_root path_of_calling_controller = File.dirname(caller[0].split(/:\d+:/).first) path_of_controller_root = path_of_calling_controller.sub(/#{controller_path.split("/")[0..-2]}$/, "") # " (for ruby-mode) + self.template_root = path_of_controller_root end end @@ -68,57 +76,60 @@ module ActionController #:nodoc: def render_component_as_string(options) #:doc: component_logging(options) do response = component_response(options, false) + if redirected = response.redirected_to - render_component_as_string redirected + render_component_as_string(redirected) else response.body end - end + end end - + private - def component_response(options, reuse_response) - c_class = component_class(options) - c_request = request_for_component(c_class.controller_name, options) - c_response = reuse_response ? @response : @response.dup - c_class.process(c_request, c_response, self) + def component_response(options, reuse_response) + klass = component_class(options) + request = request_for_component(klass.controller_name, options) + response = reuse_response ? @response : @response.dup + + klass.process(request, response, self) + end + + # determine the controller class for the component request + def component_class(options) + if controller = options[:controller] + controller.is_a?(Class) ? controller : "#{controller.camelize}Controller".constantize + else + self.class + end + end + + # Create a new request object based on the current request. + # The new request inherits the session from the current request, + # bypassing any session options set for the component controller's class + def request_for_component(controller_name, options) + request = @request.dup + request.session = @request.session + + request.instance_variable_set( + :@parameters, + (options[:params] || {}).with_indifferent_access.regular_update( + "controller" => controller_name, "action" => options[:action], "id" => options[:id] + ) + ) + + request end - - # determine the controller class for the component request - def component_class(options) - if controller = options[:controller] - if controller.is_a? Class - controller - else - "#{controller.camelize}Controller".constantize - end + + def component_logging(options) + if logger + logger.info "Start rendering component (#{options.inspect}): " + result = yield + logger.info "\n\nEnd of component rendering" + result else - self.class + yield end end - - # Create a new request object based on the current request. - # The new request inherits the session from the current request, - # bypassing any session options set for the component controller's class - def request_for_component(controller_name, options) - sub_request = @request.dup - sub_request.session = @request.session - sub_request.instance_variable_set(:@parameters, - (options[:params] || {}).with_indifferent_access.regular_update( - "controller" => controller_name, "action" => options[:action], "id" => options[:id]) - ) - sub_request - end - - - def component_logging(options) - unless logger then yield else - logger.info("Start rendering component (#{options.inspect}): ") - result = yield - logger.info("\n\nEnd of component rendering") - result - end - end end end end -- cgit v1.2.3