Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #10195: killing_components_once_and_for_all.diff

File killing_components_once_and_for_all.diff, 11.8 kB (added by sjgman9, 1 year ago)
  • actionpack/test/controller/components_test.rb

    old new  
    1 require File.dirname(__FILE__) + '/../abstract_unit' 
    2  
    3 class CallerController < ActionController::Base 
    4   def calling_from_controller 
    5     render_component(:controller => "callee", :action => "being_called") 
    6   end 
    7  
    8   def calling_from_controller_with_params 
    9     render_component(:controller => "callee", :action => "being_called", :params => { "name" => "David" }) 
    10   end 
    11  
    12   def calling_from_controller_with_different_status_code 
    13     render_component(:controller => "callee", :action => "blowing_up") 
    14   end 
    15  
    16   def calling_from_template 
    17     render :inline => "Ring, ring: <%= render_component(:controller => 'callee', :action => 'being_called') %>" 
    18   end 
    19  
    20   def internal_caller 
    21     render :inline => "Are you there? <%= render_component(:action => 'internal_callee') %>" 
    22   end 
    23  
    24   def internal_callee 
    25     render :text => "Yes, ma'am" 
    26   end 
    27  
    28   def set_flash 
    29     render_component(:controller => "callee", :action => "set_flash") 
    30   end 
    31  
    32   def use_flash 
    33     render_component(:controller => "callee", :action => "use_flash") 
    34   end 
    35  
    36   def calling_redirected 
    37     render_component(:controller => "callee", :action => "redirected") 
    38   end 
    39  
    40   def calling_redirected_as_string 
    41     render :inline => "<%= render_component(:controller => 'callee', :action => 'redirected') %>" 
    42   end 
    43  
    44   def rescue_action(e) raise end 
    45 end 
    46  
    47 class CalleeController < ActionController::Base 
    48   def being_called 
    49     render :text => "#{params[:name] || "Lady"} of the House, speaking" 
    50   end 
    51  
    52   def blowing_up 
    53     render :text => "It's game over, man, just game over, man!", :status => 500 
    54   end 
    55  
    56   def set_flash 
    57     flash[:notice] = 'My stoney baby' 
    58     render :text => 'flash is set' 
    59   end 
    60  
    61   def use_flash 
    62     render :text => flash[:notice] || 'no flash' 
    63   end 
    64  
    65   def redirected 
    66     redirect_to :controller => "callee", :action => "being_called" 
    67   end 
    68  
    69   def rescue_action(e) raise end 
    70 end 
    71  
    72 class ComponentsTest < Test::Unit::TestCase 
    73   def setup 
    74     @controller = CallerController.new 
    75     @request    = ActionController::TestRequest.new 
    76     @response   = ActionController::TestResponse.new 
    77   end 
    78  
    79   def test_calling_from_controller 
    80     get :calling_from_controller 
    81     assert_equal "Lady of the House, speaking", @response.body 
    82   end 
    83  
    84   def test_calling_from_controller_with_params 
    85     get :calling_from_controller_with_params 
    86     assert_equal "David of the House, speaking", @response.body 
    87   end 
    88  
    89   def test_calling_from_controller_with_different_status_code 
    90     get :calling_from_controller_with_different_status_code 
    91     assert_equal 500, @response.response_code 
    92   end 
    93  
    94   def test_calling_from_template 
    95     get :calling_from_template 
    96     assert_equal "Ring, ring: Lady of the House, speaking", @response.body 
    97   end 
    98  
    99   def test_etag_is_set_for_parent_template_when_calling_from_template 
    100     get :calling_from_template 
    101     expected_etag = etag_for("Ring, ring: Lady of the House, speaking") 
    102     assert_equal expected_etag, @response.headers['ETag'] 
    103   end 
    104  
    105   def test_internal_calling 
    106     get :internal_caller 
    107     assert_equal "Are you there? Yes, ma'am", @response.body 
    108   end 
    109  
    110   def test_flash 
    111     get :set_flash 
    112     assert_equal 'My stoney baby', flash[:notice] 
    113     get :use_flash 
    114     assert_equal 'My stoney baby', @response.body 
    115     get :use_flash 
    116     assert_equal 'no flash', @response.body 
    117   end 
    118  
    119   def test_component_redirect_redirects 
    120     get :calling_redirected 
    121  
    122     assert_redirected_to :action => "being_called" 
    123   end 
    124  
    125   def test_component_multiple_redirect_redirects 
    126     test_component_redirect_redirects 
    127     test_internal_calling 
    128   end 
    129  
    130   def test_component_as_string_redirect_renders_redirected_action 
    131     get :calling_redirected_as_string 
    132  
    133     assert_equal "Lady of the House, speaking", @response.body 
    134   end 
    135  
    136   protected 
    137     def etag_for(text) 
    138       %("#{Digest::MD5.hexdigest(text)}") 
    139     end 
    140 end 
  • actionpack/lib/action_controller/components.rb

    old new  
    1 module ActionController #:nodoc: 
    2   # Components allow you to call other actions for their rendered response while executing another action. You can either delegate 
    3   # the entire response rendering or you can mix a partial response in with your other content. 
    4   # 
    5   #   class WeblogController < ActionController::Base 
    6   #     # Performs a method and then lets hello_world output its render 
    7   #     def delegate_action 
    8   #       do_other_stuff_before_hello_world 
    9   #       render_component :controller => "greeter",  :action => "hello_world", :params => { :person => "david" } 
    10   #     end 
    11   #   end 
    12   # 
    13   #   class GreeterController < ActionController::Base 
    14   #     def hello_world 
    15   #       render :text => "#{params[:person]} says, Hello World!" 
    16   #     end 
    17   #   end 
    18   # 
    19   # The same can be done in a view to do a partial rendering: 
    20   # 
    21   #   Let's see a greeting: 
    22   #   <%= render_component :controller => "greeter", :action => "hello_world" %> 
    23   # 
    24   # It is also possible to specify the controller as a class constant, bypassing the inflector 
    25   # code to compute the controller class at runtime: 
    26   # 
    27   # <%= render_component :controller => GreeterController, :action => "hello_world" %> 
    28   # 
    29   # == When to use components 
    30   # 
    31   # Components should be used with care. They're significantly slower than simply splitting reusable parts into partials and 
    32   # conceptually more complicated. Don't use components as a way of separating concerns inside a single application. Instead, 
    33   # reserve components to those rare cases where you truly have reusable view and controller elements that can be employed 
    34   # across many applications at once. 
    35   # 
    36   # So to repeat: Components are a special-purpose approach that can often be replaced with better use of partials and filters. 
    37   module Components 
    38     def self.included(base) #:nodoc: 
    39       base.class_eval do 
    40         include InstanceMethods 
    41         extend ClassMethods 
    42  
    43         helper do 
    44           def render_component(options) 
    45             @controller.send!(:render_component_as_string, options) 
    46           end 
    47         end 
    48  
    49         # If this controller was instantiated to process a component request, 
    50         # +parent_controller+ points to the instantiator of this controller. 
    51         attr_accessor :parent_controller 
    52  
    53         alias_method_chain :process_cleanup, :components 
    54         alias_method_chain :set_session_options, :components 
    55         alias_method_chain :flash, :components 
    56  
    57         alias_method :component_request?, :parent_controller 
    58       end 
    59     end 
    60  
    61     module ClassMethods 
    62       # Track parent controller to identify component requests 
    63       def process_with_components(request, response, parent_controller = nil) #:nodoc: 
    64         controller = new 
    65         controller.parent_controller = parent_controller 
    66         controller.process(request, response) 
    67       end 
    68     end 
    69  
    70     module InstanceMethods 
    71       # Extracts the action_name from the request parameters and performs that action. 
    72       def process_with_components(request, response, method = :perform_action, *arguments) #:nodoc: 
    73         flash.discard if component_request? 
    74         process_without_components(request, response, method, *arguments) 
    75       end 
    76  
    77       protected 
    78         # Renders the component specified as the response for the current method 
    79         def render_component(options) #:doc: 
    80           component_logging(options) do 
    81             render_for_text(component_response(options, true).body, response.headers["Status"]) 
    82           end 
    83         end 
    84  
    85         # Returns the component response as a string 
    86         def render_component_as_string(options) #:doc: 
    87           component_logging(options) do 
    88             response = component_response(options, false) 
    89  
    90             if redirected = response.redirected_to 
    91               render_component_as_string(redirected) 
    92             else 
    93               response.body 
    94             end 
    95           end 
    96         end 
    97  
    98         def flash_with_components(refresh = false) #:nodoc: 
    99           if !defined?(@_flash) || refresh 
    100             @_flash = 
    101               if defined?(@parent_controller) 
    102                 @parent_controller.flash 
    103               else 
    104                 flash_without_components 
    105               end 
    106           end 
    107           @_flash 
    108         end 
    109  
    110       private 
    111         def component_response(options, reuse_response) 
    112           klass    = component_class(options) 
    113           request  = request_for_component(klass.controller_name, options) 
    114           new_response = reuse_response ? response : response.dup 
    115  
    116           klass.process_with_components(request, new_response, self) 
    117         end 
    118  
    119         # determine the controller class for the component request 
    120         def component_class(options) 
    121           if controller = options[:controller] 
    122             controller.is_a?(Class) ? controller : "#{controller.camelize}Controller".constantize 
    123           else 
    124             self.class 
    125           end 
    126         end 
    127  
    128         # Create a new request object based on the current request. 
    129         # The new request inherits the session from the current request, 
    130         # bypassing any session options set for the component controller's class 
    131         def request_for_component(controller_name, options) 
    132           new_request         = request.dup 
    133           new_request.session = request.session 
    134  
    135           new_request.instance_variable_set( 
    136             :@parameters, 
    137             (options[:params] || {}).with_indifferent_access.update( 
    138               "controller" => controller_name, "action" => options[:action], "id" => options[:id] 
    139             ) 
    140           ) 
    141  
    142           new_request 
    143         end 
    144  
    145         def component_logging(options) 
    146           if logger 
    147             logger.info "Start rendering component (#{options.inspect}): " 
    148             result = yield 
    149             logger.info "\n\nEnd of component rendering" 
    150             result 
    151           else 
    152             yield 
    153           end 
    154         end 
    155  
    156         def set_session_options_with_components(request) 
    157           set_session_options_without_components(request) unless component_request? 
    158         end 
    159  
    160         def process_cleanup_with_components 
    161           process_cleanup_without_components unless component_request? 
    162         end 
    163     end 
    164   end 
    165 end 
  • actionpack/lib/action_controller/base.rb

    old new  
    515515        assign_default_content_type_and_charset 
    516516 
    517517        response.request = request 
    518         response.prepare! unless component_request? 
     518        response.prepare! 
    519519        response 
    520520      ensure 
    521521        process_cleanup 
  • actionpack/lib/action_controller.rb

    old new  
    5252require 'action_controller/streaming' 
    5353require 'action_controller/session_management' 
    5454require 'action_controller/http_authentication' 
    55 require 'action_controller/components' 
    5655require 'action_controller/record_identifier' 
    5756require 'action_controller/request_forgery_protection' 
    5857 
     
    7372  include ActionController::Streaming 
    7473  include ActionController::SessionManagement 
    7574  include ActionController::HttpAuthentication::Basic::ControllerMethods 
    76   include ActionController::Components 
    7775  include ActionController::RecordIdentifier 
    7876  include ActionController::RequestForgeryProtection 
    7977end