In Rails 3, want to get the HTML output of calling a controller's action
Is it possible for me to call a controllers action program开发者_StackOverflowatically and get the HTML output?
Here's a rails2 example that might get you a bit closer
lib/render_url_to_string.rb
if !defined?(ActionController::Integration::Session)
require "action_controller/integration"
end
class Rack::Lint
def call(*args)
@app.call(*args)
end
end
module RenderURLToString
def self.included(base)
base.send(:include, RenderURLToString::InstanceMethods)
base.extend( RenderURLToString::ClassMethods)
end
module ClassMethods
# This method sets the default hostname to render templates
# with. Use this to ensure the output urls in your templates
# are getting the right host.
#
def set_default_render_hostname(host)
RenderURLToString::Settings.hostname = host
end
end
module InstanceMethods
# This method renders a given URL within your site to a string.
# Invoke the method with the form
# render_url_to_string("/path/to/resource.ext")
# The method supports the following optional parameters, passed in
# as a symbol hash.
#
# :headers => A hash of HTTP headers
# Defaults to nil
# :params => A hash of URL parameters, or a string of URL
# parameters "?foo=bar&baz=bo"
# Defaults to nil
# :method => A symbol or string representing which HTTP method
# to use. Must be :get, :post, :put or :delete
# Defaults to :get
# :environment => A request environment to pass to the Dispatcher.
# You will rarely need to use this option; if you
# are calling the method inside of a Rails template
# or controller, the method will use the
# current request, extracting the relevant parts
# for its own use.
# :host => The host name to use for resolving URL creation
# Defaults to www.example.com
#
#
# The method returns an array with two elements. The first
# element is the integer status code (200, 404, 500) of the
# attempt to process the URL, and the second element is the
# string result of the body processed. An example return value of
# a successful request would be:
# [200, "<html><head><title>Foo!</title></head><body></body></html>"]
#
# whereas an example of a failed request would be:
# [500, "<html><head><title>The request failed</title><body></body></html>"]
#
# Examples:
#
# Renders the url /foo/bar.baz
# render_url_to_string("/foo/bar.baz")
#
# Renders the url /foo/bar.baz?wocca=wocca!
# render_url_to_string("/foo/bar.baz", :params => { :wocca => "wocca!" }
#
# Renders the url /foo/bar.baz with form parameter wocca = whoopiepie
# render_url_to_string("/foo/bar.baz",
# :params => { :wocca => "whoopiepie" }
# :method => :post)
#
# Renders the url /foo/bar.baz with form parameter wocca =
# whoopiepie and host set to "www.yahoo.com"
# render_url_to_string("/foo/bar.baz",
# :host => "www.yahoo.com",
# :params => { :wocca => "whoopiepie" }
# :method => :post)
#
def render_url_to_string(url, *args)
options = args.extract_options!
method = (options.delete(:method) || :get)
if method.is_a?(String)
method = method.downcase.to_sym
end
headers = options.delete(:headers)
params = options.delete(:params)
environment =
raise "Invalid method, must be GET, POST, PUT or DELETE" unless [ :get, :post, :put, :delete ].include?(method)
app = RenderURLToString::Settings.app
reset_host = app.host
if host = (options.delete(:host) || RenderURLToString::Settings.hostname)
app.host = host
end
if e = options.delete(:environment)
RenderURLToString::Settings.set_current_app_environment(e)
elsif self.respond_to?(:request) && request.env
RenderURLToString::Settings.set_current_app_environment(request.env)
else
RenderURLToString::Settings.set_current_app_environment(ENV)
end
status = app.send(method.to_sym, url, params, headers)
app.host = reset_host
return [status, RenderURLToString::Settings.app.body]
end
end
private
class Settings
IGNORED_ENVIRONMENT_KEYS = ["REQUEST_PATH", "action_controller.request.request_parameters", "PATH_INFO", "rack.request", "rack.routing_args", "rack.multithread","rack.request.query_hash","REQUEST_METHOD", "action_controller.request.query_parameters", "action_controller.rescue.request", "rack.request.query_string", "action_controller.rescue.response","rack.input", "QUERY_STRING", "rack.errors", "REQUEST_URI", "SCRIPT_NAME"]
def self.app=(app)
@app = app
end
def self.app
unless @app
# We don't want to deadlock the server when trying
# to process this internal request
# THIS IS MUCKING WITH INTERNAL RAILS REQUEST DISPATCHING LOGIC
# AND AS SUCH SHOULD NOT BE MESSED WITH UNLESS YOU
# PLAN ON FIXING BUGS IN THE FUTURE
dispatcher = ActionController::Dispatcher.new(self.stringio)
dispatcher.instance_eval do |instance|
def set_my_env(e)
@my_env = {}
e.each do |k, v|
@my_env[k] = v unless IGNORED_ENVIRONMENT_KEYS.include?(k)
end
end
def call(e)
@env = e.merge(@my_env)
self.dispatch
end
end
@app = ActionController::Integration::Session.new(dispatcher)
end
@app
end
def self.set_current_app_environment(env)
self.app.application.set_my_env(env)
end
def self.hostname=(host)
@host = host
end
def self.hostname
@host
end
def self.stringio
StringIO.new
end
end
end
精彩评论