LoginSignup
4
0

More than 1 year has passed since last update.

controllerのインスタンス変数をなんでviewでも使えるの?

Last updated at Posted at 2022-12-18

はじめに

Railsではcontrollerで定義したインスタンス変数をview側で使うことができますが、最近、ふと「これなんで?」と思ったのでrailsの中身を見てみようと思います。

コードリーディング

作成されるcontrollerApplicationControllerを継承していて、ApplicationControllerActionController::Baseを継承しているので、ActionController::Baseを見にいきます。

actionpack/lib/action_controller/base.rb
# == Renders
  #
  # Action Controller sends content to the user by using one of five rendering methods. The most versatile and common is the rendering
  # of a template. Included in the Action Pack is the Action View, which enables rendering of ERB templates. It's automatically configured.
  # The controller passes objects to the view by assigning instance variables:
  #
  #   def show
  #     @post = Post.find(params[:id])
  #   end
  #
  # Which are then automatically available to the view:
  #
  #   Title: <%= @post.title %>
  #
  # You don't have to rely on the automated rendering. For example, actions that could result in the rendering of different templates
  # will use the manual rendering methods:
  #
  #   def search
  #     @results = Search.find(params[:query])
  #     case @results.count
  #       when 0 then render action: "no_results"
  #       when 1 then render action: "show"
  #       when 2..10 then render action: "show_many"
  #     end
  #   end
  #
  # Read more about writing ERB and Builder templates in ActionView::Base.

The controller passes objects to the view by assigning instance variables:

instance variableassignすることで、controllerview側にオブジェクトを渡すと書かれています。
まさにこのことです。

Read more about writing ERB and Builder templates in ActionView::Base.

もっと知りたかったらActionView::Baseを見に行けと書かれているので見にいきます。

actionview/lib/action_view/base.rb
    def initialize(lookup_context, assigns, controller) # :nodoc:
        @_config = ActiveSupport::InheritableOptions.new
        
        @lookup_context = lookup_context
        
        @view_renderer = ActionView::Renderer.new @lookup_context
        @current_template = nil
        
        assign(assigns)
        assign_controller(controller)
        _prepare_context
    end

ActionView::Baseクラスのインスタンスが生成されるときの処理内容です。

actionview/lib/action_view/base.rb
    def assign(new_assigns) # :nodoc:
        @_assigns = new_assigns.each { |key, value| instance_variable_set("@#{key}", value) }
    end

今回対象となるのはassignメソッドです。(ここはエスパーしました。)
ActionView::Baseのインスタンス変数@_assignsに、ActionView::Baseinitializeされた際の引数assignsを代入しています。
次はActionView::Baseinitializeされるところを見にいきます。

actionview/lib/action_view/rendering.rb
    def view_context
        view_context_class.new(lookup_context, view_assigns, self)
    end

ActionView::Baseview_contextメソッドによって、initializeされます。(ここはまた別の記事で書きます。)
view_contextメソッドはそのすぐ下にある_render_templateメソッドから呼び出されていて、このメソッドはレスポンスのbodyを作るメソッドです。
view_contextに渡される第2引数がassignメソッドに渡される引数(view側で使うことができるインスタンス変数)です。

view_assignsメソッドを見にいきます。

actionpack/lib/abstract_controller/rendering.rb
    def view_assigns
      variables = instance_variables - _protected_ivars

      variables.each_with_object({}) do |name, hash|
        hash[name.slice(1, name.length)] = instance_variable_get(name)
      end
    end

view_assignsメソッドは最終的に変数variablesを返しますが、その中身はinstance_variablesで、これはRuby由来のメソッドでその呼び出し元のオブジェクトのインスタンス変数を返すメソッドです。

このときの呼び出し元のオブジェクトはcontrollerのインスタンスなので、controllerで定義したインスタンス変数がそれにあたります。
ここでcontrollerのインスタンス変数がview側に渡されています。

参考にしたサイト

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0