renderが省略されてて眠れなくなったので調査

## はじめに
この記事は[エムスリーキャリア Advent Calendar 2019](https://qiita.com/advent-calendar/2019/m3c) 18日目の記事です。

エニジニアリンググループのおどです。
新卒入社した会社を8月に辞め、エムスリーキャリアに転職しました。
転職を機にLaravelエンジニアからRailsエンジニアに転身。

今回は利用するフレームワークがLaravelからRuby on Railsに変わり、つまずいたところを軽く深堀してみようと思います。

## 何に詰まったのか

入社して最初、簡単な文言修正のタスクからアサインされました。

「お、viewファイル見て文字直すだけとか簡単じゃん」

Laravelで開発をしてたときのようにroutingファイルを見て、controllerにたどり着きました。

``` home_controller.rb
class HomeController < ApplicationController
  def index
  end
end
```

どのファイルをレンダリングしているんだ…

気になって眠れない日々が始まりました。

Laravelはわかりやすかったな…

``` HomeController.php
<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;

class HomeController extends Controller
{
    public function index()
    {
        return view('home.index');
    }
}
```

## 調査
binding.pryを使ってトレースしていきたいと思います。

まず、railsではcontrollerのメソッドが終了すると、send_actionというメソッドが呼ばれます。

``` actionpack-5.2.4/lib/action_controller/metal/basic_implicit_render.rb
# frozen_string_literal: true

module ActionController
  module BasicImplicitRender # :nodoc:
    def send_action(method, *args)
      super.tap { default_render unless performed? }
    end

    def default_render(*args)
      head :no_content
    end
  end
end
```

controllerのメソッド内でrenderを1度も実行していないと、`performed?`が`false`を返します。

basic_implicit_renderをincludeした`action_controller/metal/implicit_render.rb`内に同名のdefault_renderが定義されていて、そこからrenderを呼び出します。

ここで呼ばれるrenderは、自分でcontrollerのメソッド内で呼び出したrenderと同じです。(`action_controller/metal/instrumentation.rb`)

```action_controller/metal/instrumentation.rb
    def render(*args)
      render_output = nil
      self.view_runtime = cleanup_view_runtime do
        Benchmark.ms { render_output = super }
      end
      render_output
    end
```

さらに追っていくと、`abstract_controller/rendering.rb`内のrenderメソッドにたどり着きます。

```abstract_controller/rendering.rb
    def render(*args, &block)
      options = _normalize_render(*args, &block)
      rendered_body = render_to_body(options)
      if options[:html]
        _set_html_content_type
      else
        _set_rendered_content_type rendered_format
      end
      self.response_body = rendered_body
    end
```

renderを省略した場合、この`render_to_body`メソッドに渡る引数が異なってきます。

```shell
# renderを省略した場合
[1] pry(#<HomeController>)> options
=> {:prefixes=>["home", "application"], :template=>"index", :layout=>#<Proc:0x00007f481d31fa80@/myapp/vendor/bundle/ruby/2.6.0/gems/actionview-5.2.4/lib/action_view/layouts.rb:392>}

# renderを省略しなかった場合
[1] pry(#<HomeController>)> options
=> {:action=>"index", :prefixes=>["home", "application"], :template=>"index", :layout=>#<Proc:0x00007f481ef20a90@/myapp/vendor/bundle/ruby/2.6.0/gems/actionview-5.2.4/lib/action_view/layouts.rb:392>}
```

渡される引数を見ると、prefixesに呼び出したコントローラ名、templateにメソッド名が格納されているのが分かります。
renderを省略するとprefixesとtemplateから、省略しないとprefixesとactionからビューファイルの名前を組み立ててレンダリングしてくれているようです。


## わかったこと
* renderを省略すると呼び出しもとからファイル名を組み立ててレンダリングしてくれる

## ちなみに
省略した場合に呼ばれるrenderは通常と同じrenderなので、引数だけを省略しても同じ挙動になりました。

```home_controller.rb
class HomeController < ApplicationController
  def index
    render
  end
end
```

## 感想
たくさんのファイルが継承されていて、覚えられなくて大変でした。
これで安心してrenderを省略でき、ぐっすり眠れそうです。

ご指摘や「ここ間違ってるよ！」、感想など募集中なので気軽にコメントください。


## 環境
Rails 5.2.4
ruby 2.6.5

## 参考URL
こちらの記事でもっと詳しく追っていたので、さらに興味がある方はこちらも見てみてください。
[Railsはどのようにテンプレートを見つけているか
](https://qiita.com/ngtk/items/cd406961cf62531a81c5)