2005-02-19 15:29:55 -05:00
|
|
|
module ActionController #:nodoc:
|
2006-02-11 20:06:45 -05:00
|
|
|
# Components allow you to call other actions for their rendered response while executing another action. You can either delegate
|
2005-02-23 20:29:43 -05:00
|
|
|
# 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
|
2006-02-11 20:06:45 -05:00
|
|
|
# render_component :controller => "greeter", :action => "hello_world", :params => { :person => "david" }
|
2005-02-23 20:29:43 -05:00
|
|
|
# end
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# class GreeterController < ActionController::Base
|
|
|
|
# def hello_world
|
2006-02-11 20:06:45 -05:00
|
|
|
# render :text => "#{params[:person]} says, Hello World!"
|
2005-02-23 20:29:43 -05:00
|
|
|
# end
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# The same can be done in a view to do a partial rendering:
|
2007-03-13 00:46:12 -04:00
|
|
|
#
|
|
|
|
# Let's see a greeting:
|
2005-02-23 20:29:43 -05:00
|
|
|
# <%= render_component :controller => "greeter", :action => "hello_world" %>
|
2006-02-09 15:05:11 -05:00
|
|
|
#
|
|
|
|
# It is also possible to specify the controller as a class constant, bypassing the inflector
|
2006-02-11 20:06:45 -05:00
|
|
|
# code to compute the controller class at runtime:
|
2007-03-13 00:46:12 -04:00
|
|
|
#
|
2006-02-09 15:05:11 -05:00
|
|
|
# <%= render_component :controller => GreeterController, :action => "hello_world" %>
|
2006-02-11 20:06:45 -05:00
|
|
|
#
|
|
|
|
# == 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,
|
2007-03-13 00:46:12 -04:00
|
|
|
# reserve components to those rare cases where you truly have reusable view and controller elements that can be employed
|
2006-02-11 20:06:45 -05:00
|
|
|
# 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.
|
2005-02-23 20:29:43 -05:00
|
|
|
module Components
|
2006-02-11 19:46:01 -05:00
|
|
|
def self.included(base) #:nodoc:
|
2007-10-02 01:32:14 -04:00
|
|
|
base.class_eval do
|
|
|
|
include InstanceMethods
|
|
|
|
extend ClassMethods
|
2006-02-11 19:46:01 -05:00
|
|
|
|
2007-10-02 01:32:14 -04:00
|
|
|
helper do
|
|
|
|
def render_component(options)
|
|
|
|
@controller.send!(:render_component_as_string, options)
|
|
|
|
end
|
2005-02-20 08:50:13 -05:00
|
|
|
end
|
2007-03-13 00:46:12 -04:00
|
|
|
|
2007-10-02 01:32:14 -04:00
|
|
|
# If this controller was instantiated to process a component request,
|
|
|
|
# +parent_controller+ points to the instantiator of this controller.
|
|
|
|
attr_accessor :parent_controller
|
2007-03-13 00:46:12 -04:00
|
|
|
|
2006-04-29 16:20:22 -04:00
|
|
|
alias_method_chain :process_cleanup, :components
|
|
|
|
alias_method_chain :set_session_options, :components
|
|
|
|
alias_method_chain :flash, :components
|
2006-03-19 23:01:10 -05:00
|
|
|
|
2007-03-13 00:46:12 -04:00
|
|
|
alias_method :component_request?, :parent_controller
|
2006-02-12 00:51:02 -05:00
|
|
|
end
|
2005-02-19 15:29:55 -05:00
|
|
|
end
|
|
|
|
|
2006-02-11 19:46:01 -05:00
|
|
|
module ClassMethods
|
2006-02-12 00:51:02 -05:00
|
|
|
# Track parent controller to identify component requests
|
|
|
|
def process_with_components(request, response, parent_controller = nil) #:nodoc:
|
|
|
|
controller = new
|
|
|
|
controller.parent_controller = parent_controller
|
|
|
|
controller.process(request, response)
|
|
|
|
end
|
2006-02-11 19:46:01 -05:00
|
|
|
end
|
2005-02-23 10:26:48 -05:00
|
|
|
|
2006-02-11 19:46:01 -05:00
|
|
|
module InstanceMethods
|
2006-02-12 00:51:02 -05:00
|
|
|
# Extracts the action_name from the request parameters and performs that action.
|
|
|
|
def process_with_components(request, response, method = :perform_action, *arguments) #:nodoc:
|
|
|
|
flash.discard if component_request?
|
|
|
|
process_without_components(request, response, method, *arguments)
|
|
|
|
end
|
2007-03-13 00:46:12 -04:00
|
|
|
|
2006-02-11 19:46:01 -05:00
|
|
|
protected
|
|
|
|
# Renders the component specified as the response for the current method
|
|
|
|
def render_component(options) #:doc:
|
|
|
|
component_logging(options) do
|
2007-09-02 20:18:30 -04:00
|
|
|
render_for_text(component_response(options, true).body, response.headers["Status"])
|
2005-10-14 22:53:21 -04:00
|
|
|
end
|
2006-02-11 19:46:01 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
# Returns the component response as a string
|
|
|
|
def render_component_as_string(options) #:doc:
|
|
|
|
component_logging(options) do
|
|
|
|
response = component_response(options, false)
|
2006-02-11 20:06:45 -05:00
|
|
|
|
2006-02-11 19:46:01 -05:00
|
|
|
if redirected = response.redirected_to
|
2006-02-11 20:06:45 -05:00
|
|
|
render_component_as_string(redirected)
|
2006-02-11 19:46:01 -05:00
|
|
|
else
|
|
|
|
response.body
|
|
|
|
end
|
2006-02-11 20:06:45 -05:00
|
|
|
end
|
2006-02-12 01:11:17 -05:00
|
|
|
end
|
|
|
|
|
2006-03-27 22:19:27 -05:00
|
|
|
def flash_with_components(refresh = false) #:nodoc:
|
2006-08-07 02:11:56 -04:00
|
|
|
if !defined?(@_flash) || refresh
|
|
|
|
@_flash =
|
2006-07-08 14:14:49 -04:00
|
|
|
if defined?(@parent_controller)
|
2006-02-12 01:11:17 -05:00
|
|
|
@parent_controller.flash
|
|
|
|
else
|
|
|
|
flash_without_components
|
|
|
|
end
|
|
|
|
end
|
2006-08-07 02:11:56 -04:00
|
|
|
@_flash
|
2006-02-11 19:46:01 -05:00
|
|
|
end
|
2006-02-11 20:06:45 -05:00
|
|
|
|
2006-02-11 19:46:01 -05:00
|
|
|
private
|
2006-02-11 20:06:45 -05:00
|
|
|
def component_response(options, reuse_response)
|
|
|
|
klass = component_class(options)
|
|
|
|
request = request_for_component(klass.controller_name, options)
|
2006-09-29 04:26:45 -04:00
|
|
|
new_response = reuse_response ? response : response.dup
|
2006-02-12 00:51:02 -05:00
|
|
|
|
2006-09-29 04:26:45 -04:00
|
|
|
klass.process_with_components(request, new_response, self)
|
2006-02-11 20:06:45 -05:00
|
|
|
end
|
2006-09-29 04:26:45 -04:00
|
|
|
|
2006-02-11 20:06:45 -05:00
|
|
|
# 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
|
2006-09-29 03:34:02 -04:00
|
|
|
|
2006-02-11 20:06:45 -05:00
|
|
|
# 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)
|
2006-09-29 03:34:02 -04:00
|
|
|
new_request = request.dup
|
|
|
|
new_request.session = request.session
|
|
|
|
|
|
|
|
new_request.instance_variable_set(
|
2006-02-11 20:06:45 -05:00
|
|
|
:@parameters,
|
2006-03-18 11:11:21 -05:00
|
|
|
(options[:params] || {}).with_indifferent_access.update(
|
2006-02-11 20:06:45 -05:00
|
|
|
"controller" => controller_name, "action" => options[:action], "id" => options[:id]
|
|
|
|
)
|
|
|
|
)
|
2006-09-29 03:34:02 -04:00
|
|
|
|
|
|
|
new_request
|
2006-02-12 00:51:02 -05:00
|
|
|
end
|
2006-02-11 20:06:45 -05:00
|
|
|
|
2006-02-12 00:51:02 -05:00
|
|
|
def component_logging(options)
|
|
|
|
if logger
|
|
|
|
logger.info "Start rendering component (#{options.inspect}): "
|
|
|
|
result = yield
|
|
|
|
logger.info "\n\nEnd of component rendering"
|
|
|
|
result
|
|
|
|
else
|
|
|
|
yield
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def set_session_options_with_components(request)
|
|
|
|
set_session_options_without_components(request) unless component_request?
|
|
|
|
end
|
|
|
|
|
|
|
|
def process_cleanup_with_components
|
|
|
|
process_cleanup_without_components unless component_request?
|
|
|
|
end
|
2006-02-11 19:46:01 -05:00
|
|
|
end
|
2005-02-19 15:29:55 -05:00
|
|
|
end
|
2007-10-02 01:32:14 -04:00
|
|
|
end
|