开发者

In Rails 3, want to get the HTML output of calling a controller's action

开发者 https://www.devze.com 2023-02-08 13:17 出处:网络
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

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
0

精彩评论

暂无评论...
验证码 换一张
取 消