• 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

This article was migrated from http://rails.office.drecom.jp/takiuchi/archive/39

render_componentの挙動を調査する必要があったので、メモを残しておきます。 render_componentは、いわゆるWidgetのような、再利用可能なGUI部品をレンダリングするメソッドです。以下に、要点だけ抜き出したソースを示します。

長いので先に結論だけ書いておくと、render_componentでレンダリングされるコンポーネントのコードから、呼び出し元の外部コントローラにアクセスするには、ActionController#parent_controllerを介せばOKです。

$ vim vendor/rails/actionpack/lib/action_controller/components.rb
module ActionController
module Components
  base.helper do
    def render_component(options)
      @controller.send(:render_component_as_string, options)
    end
  end
  module ClassMethods
    # Track parent controller to identify component requests
    def process_with_components(request, response, parent_controller = nil)
      controller = new
      controller.parent_controller = parent_controller
      controller.process(request, response)
    end
  end
  module InstanceMethods
    # Extracts the action_name from the request parameters and performs that action.
    def process_with_components(request, response, method = :perform_action, *arguments)
      flash.discard if component_request?
      process_without_components(request, response, method, *arguments)
    end
  protected
    # Returns the component response as a string
    def render_component_as_string(options)
      component_logging(options) do
        response = component_response(options, false)
        if redirected = response.redirected_to
          render_component_as_string(redirected)
        else
          response.body
        end
      end
    end
  private
    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_with_components(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.update(
          "controller" => controller_name, "action" => options[:action],
          "id" => options[:id]))
      request
    end
  end
end

request_for_componentの中身:
with_indifferent_accessは、ActiveSupportによるHashの拡張機能で、Symbolと文字列のkeyを同一視できるようにするものです。instance_variable_setというのは、RubyのObjectクラスのメソッドで、こんな感じにインスタンス変数を外部から設定できてしまいます:

obj = Object.new
p obj.instance_variable_set("@foo", 1)  # => 1
p obj.instance_variable_set(:@foo, 2)   # => 2
p obj.instance_variable_get(:@foo)      # => 2

というわけで、上記のようにcontrolleractionidの指定を挿げ替えてrequestオブジェクトを偽装しているわけです。

そして、最終的にklass.process_with_components(request, response, self)が呼び出され、render_componentの呼び出し元のcontrollerparent_controllerに設定し、制御を実行しています。

したがって、レンダリングされるコンポーネントの内部からは、parent_controllerを介して呼び出し元のcontrollerとやり取りを行う事ができます。

This article was migrated from http://rails.office.drecom.jp/takiuchi/archive/39

posted by Png genki on Wed 7 Jun 2006 at 01:37
Contents
render_componentの挙動に関するメモ
Comments
瀧内元気: MacOS版は以下にあります * [genki/ViMouse](https://githu... '23-1
dsjf: https://gist.github.com/6bf1bf2c3cbb5eb6e7a7 これ... '13-1
瀧内元気: おお、チェックしてみます。thx! '11-12
overisland: Reeder for iPhone もこの UI を実装していますね。 '11-12
瀧内元気: その情報は見たのですが、以下のサイトによると、現在はまた必要になってるっぽいんですよね。 ... '11-12
Services from s21g
twpro(ツイプロ)
Twitterプロフィールを快適検索
地価2009
土地の値段を調べてみよう
MyRestaurant
自分だけのレストラン手帳
Formula
ブログに数式を埋め込める数式コミュニティ