はじめに
Railsではcontroller
で定義したインスタンス変数をview
側で使うことができますが、最近、ふと「これなんで?」と思ったのでrailsの中身を見てみようと思います。
コードリーディング
作成されるcontroller
はApplicationController
を継承していて、ApplicationController
はActionController::Base
を継承しているので、ActionController::Base
を見にいきます。
# == 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 variable
をassign
することで、controller
はview
側にオブジェクトを渡すと書かれています。
まさにこのことです。
Read more about writing ERB and Builder templates in ActionView::Base.
もっと知りたかったらActionView::Base
を見に行けと書かれているので見にいきます。
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
クラスのインスタンスが生成されるときの処理内容です。
def assign(new_assigns) # :nodoc:
@_assigns = new_assigns.each { |key, value| instance_variable_set("@#{key}", value) }
end
今回対象となるのはassign
メソッドです。(ここはエスパーしました。)
ActionView::Base
のインスタンス変数@_assigns
に、ActionView::Base
がinitialize
された際の引数assigns
を代入しています。
次はActionView::Base
がinitialize
されるところを見にいきます。
def view_context
view_context_class.new(lookup_context, view_assigns, self)
end
ActionView::Base
はview_context
メソッドによって、initialize
されます。(ここはまた別の記事で書きます。)
view_context
メソッドはそのすぐ下にある_render_template
メソッドから呼び出されていて、このメソッドはレスポンスのbodyを作るメソッドです。
view_context
に渡される第2引数がassign
メソッドに渡される引数(view側で使うことができるインスタンス変数)です。
view_assigns
メソッドを見にいきます。
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
側に渡されています。
参考にしたサイト