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 genki genki on Wed 7 Jun 2006 at 01:37 with 0 comments

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

ふつうのHaskell写経会に行ってきました。サイトはこの辺でしょうか?

12〜14人ぐらい集まって、淡々とペア写経をしました。SICPと比べるとだいぶテンポが速そうですね。3章の始めぐらいまで進みました。

ghci

Prelude> :t length
length :: [a] -> Int

のようにすると出てくる型変数(type variable)の[a], [b], ...というのが26個以上ある場合は枯渇しないんだろうか(ものすごくどうでも良いことなのですが、なんだかとても気になったのです)、という素朴な疑問に遭遇したので、角谷さんと一緒にちょっと調べたりしていました。

しかしよく考えると、この[a]とか[b]というのは、関数の型宣言時に人間がつけた記号をそのまま返しているだけのようなので、そんな心配はするまでも無かったようです。例えば;

foo :: [bar] -> [baz] -> [qux]

というような宣言をされていれば、ghci:tをしたときにはそのまま出てくるだけなんですね。

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

posted by genki genki on Tue 6 Jun 2006 at 22:18 with 0 comments