【Rails】renderメソッドの使い方を徹底解説!

Rails

renderメソッドとは

呼び出すテンプレート(ビュー)ファイルを指定するメソッドです。
コントローラー・ビューどちらでも使うことができます。

railsではコントローラーのアクションが動くと、その後同名のビューファイルが呼び出され表示されます。
その際、コントローラーやビューで特定のビューファイルをレンダリングしたい時に使用します。

レンダリング(rendering)とは

rendering
レンダリングとはビューファイルから最終的にhtmlにコンパイルされたモノをブラウザで読み込んで表示させることを言います。
ビューファイルはただの文字の羅列なので、そのまま表示しても文字しか表示されません。
ですが、google chromeやsafariなどのブラウザがそのコード通りに見た目を作成し、ユーザーに見た目を返してくれます。
その流れをレンダリングと呼びます。

renderメソッドはそのレンダリングする元となるファイルを指定することができるメソッドです。
renderメソッドが実行されると現在のhtmlのコードが、renderメソッドで指定したビューファイルのhtmlに上書きされて表示されるイメージです。

renderメソッドの使い方

renderメソッドは下記のように記述します。

ruby
1
render ファイル名、アクション名など

具体的な書き方はビューファイルとコントローラーで異なるのでそれぞれ確認していきます。

ビューファイルでの書き方

ビューファイルでは下記のように定義します。

ruby
1
render 'ファイル名'

ビューファイルでrenderメソッドを使うときは部分テンプレートを呼び出す場合がほとんどです。

部分テンプレート

部分テンプレートとは複数のビューファイルの共通部分として作成するビューファイルです。
renderメソッドを使って部分テンプレートを呼び出す際は、部分テンプレートを呼び出していることを明示的にするためにpartialオプションを使います。

ruby
1
render partial: 'ファイル名'

部分テンプレートを呼び出す際のより詳しい書き方は部分テンプレートの使い方を徹底解説!の記事を参照してください。

コントローラー内での書き方

railsではコントローラーの各アクションが動くとアクションと同名のビューファイルがレンダリングされます。

(例)messagesコントローラーのindexアクションが動く
    ↓
   viewsフォルダ内のmessegesフォルダ内のindex.html.erbがレンダリングされる

このとき、アクションに対応するビューをレンダリングしたくないときにrenderメソッドを使用します。

renderメソッドのオプション

renderメソッドはオプションを使うことによって様々な方法でレンダリングすることができます。
それぞれのオプションの説明と実際の使い方を確認してみましょう。

action

動いたアクションとは別のアクションのテンプレートを表示させます。

ruby
1
2
3
4
5
# 例 createアクションが動いた後にnewアクションを表示させる
def create
  Message.create(message_params)
  render action: :new
end

action

これは下記のように省略して書くこともできます。

ruby
1
render :new

partial

上にも出てきましたが、明示的に部分テンプレートを呼び出すときに使用します。

ruby
1
render partial: "部分テンプレートファイル名"

partial

template

他のコントローラーのテンプレートを呼び出すときに使用します。

ruby
1
render template: "コントローラー名/アクション名"

(例)messagesコントローラーのcreateアクションが動いた後にusersコントローラーのshowアクションを表示させる

ruby
1
2
3
4
def create
  Message.create(messeage_params)
  render template: "users/show"
end

controller

layout

layoutを呼び出します。
layoutとは一つのビューファイルではなくてapplication.html.erbのような複数のビューで使われるレイアウトです。
コントローラー単位でレイアウトを切り替える場合はコントローラーに下記のように記述します。

ruby
1
layout "レイアウト名"

コントローラーの各アクションでレイアウトを指定する場合は下記のように記述します。

ruby
1
2
3
def index
  render layout: "レイアウト名"
end

layout

file

アプリケーション外のテンプレートを表示させるときに使用します。

ruby
1
render file: "別のアプリケーションの呼び出したいテンプレートファイルのパス"

file

text

文字列を直接表示させたいときに使用します。

ruby
1
render text: "ピカイチわかりやすい"

text

plain

textと同じく文字列を表示するときに使用します。
※rails5.1未満の場合はtextを使用します。

xml

オブジェクトをxml形式に変更して表示させたいときに使用します。

ruby
1
2
3
4
def index
  text = { name: "ピカわか", url: "pikawaka" }
  render xml: text
end

xml

json

オブジェクトをjson形式に変更して表示させたいときに使用します。

ruby
1
2
3
4
def index
  text = { name: "ピカわか", url: "pikawaka" }
  render json: text
end

json

inline

Rubyのコードを展開して表示させたいときに使用します。

ruby
1
2
3
4
def index
  @name = "ピカわか"
  render inline: "<%= @name %>"
end

inline

ここをtextで指定するとこうなってしまいます。

text

またビューファイルに渡す変数なので必ずインスタンス変数にしておかないとエラーになるので気をつけましょう。

status

ビューが呼び出されたときに返されるステータスコードを変更するときに使用します。
何も指定しないとちゃんとビューが返っているのでステータスコードは200です。

ruby
1
render plain: "エラーです!"

200

ruby
1
render plain: "エラーです!", status: 404

このように記述すると「エラーです!」という文字が表示され、ちゃんとビューが返っているのに404のステータスコードを返すことができます。

404

renderメソッドを使って処理を分岐させよう

コントローラーのcreateアクションやupdateアクション内で保存が失敗した時、renderメソッドを使って処理を分岐させる方法があります。

ruby
1
2
3
def create
  Message.create(message_params)
end

上のようにcreateアクション内でcreateメソッドを使って保存する場合、保存ができてもできなくてもcreateのビューがレンダリングされます。
この時の返り値は下記のようにインスタンスの情報になっています。
下の例は保存が失敗した時のものですが、保存ができてもできなくても返り値は同じです。

shell
1
2
3
4
[1] pry(main)> Message.create(text: "")
   (0.1ms)  BEGIN
   (0.2ms)  ROLLBACK
=> #<Message:0x007fc568890a50

ですがsaveメソッドを使って保存をすると保存されなかった場合、返り値としてfalseが返ります。

shell
1
2
3
4
5
6
7
8
9
10
[1] pry(main)> message = Message.new(text: "")
=> #<Message:0x007fc569b2e630
 id: nil,
 text: "",
 created_at: nil,
 updated_at: nil,
[2] pry(main)> message.save
   (0.8ms)  BEGIN
   (0.2ms)  ROLLBACK
=> false

これを利用して保存が成功した時と成功しなかった時で処理を変えることができます。

ruby
1
2
3
4
5
6
7
  def create
    @message = Message.new(message_params)
    if @message.save
      redirect_to root_path and return
    end
    render :new
  end

上のように記述すると保存が成功したときにはルートにリダイレクトさせ、失敗したときにはnewアクションで返るビュー、つまり投稿フォームを表示させることができます。
このときnewアクションを介さないでエラーがなくビューが表示できるのは同じビューファイルを再度呼び出しているからです。
つまりnewアクションが動いた後の状態が残っているから、再びnewアクションを動かす必要がないということですね。

※上のコード内の「and return」については後述します。

エラーメッセージを表示させよう

このときただ入力画面に戻っただけだとユーザーは保存されていないのに気づきません。
そんな時にはnewのビューファイルに下記のようなコードを追加するとvalidationが原因で保存できなかった時にvalidationのエラーメッセージを投稿画面に表示させることができます。

erb
1
2
3
<% if @message.errors.any? %>
   <p class="red">メッセージを入力してください。</p>
<% end %>

このように「"モデルクラスのインスタンス".errors.any?」とするとエラーが起こっているかを判定することができます。
最初に投稿画面が表示された時、@message.errorsの中身を確かめてみましょう。

ruby
1
2
3
4
  def new
    @message = Message.new
    binding.pry
  end

このようにしてnewアクションが呼び出された時の処理をbinding.pryで止めて「@message.errors」の中身を確認してみます。

shell
1
2
3
4
5
6
7
8
9
10
[1] pry(#<MessagesController>)> @message.errors
=> #<ActiveModel::Errors:0x007fbbd39c2200
 @base=
  #<Message:0x007fbbd0f1b100
   id: nil,
   text: nil,
   created_at: nil,
   updated_at: nil,
   user_id: nil>,
 @messages={}>

一番最後の行に「@messages={}」とあります。
これはエラーメッセージがないという意味です。
ですのでビューに記述した部分の「<% if @message.errors.any? %>」はfalseが返ります。

shell
1
2
[2] pry(#<TweetsController>)> @message.errors.any?
=> false

なので「メッセージを入力してください。」は表示されません。

投稿画面

それに対し、保存されなかった時を確認してみましょう。
binding.pryの位置を下記の場所に変更します。

ruby
1
2
3
4
5
6
7
8
  def create
    @message = Message.new(message_params)
    if @message.save
      redirect_to root_path and return
    end
    binding.pry
    render :new
  end

フォームに何も入力しないで送信を押し、createアクションを実行させます。
するとバリデーションに引っかかり保存されないので条件分岐によりnewのビューファイルがレンダリングされます。
その時の「@message.errors」の中身を確認してみます。

shell
1
2
3
4
5
6
7
8
9
10
[1] pry(#<MesssagesController>)> @message.errors
=> #<ActiveModel::Errors:0x007fbbd42ada68
 @base=
  #<Message:0x007fbbd16c0478
   id: nil,
   text: "",
   created_at: nil,
   updated_at: nil,
   user_id: 1>,
 @messages={:text=>["can't be blank"]}>

このように@messagesの中に文字が入りました。

shell
1
2
[2] pry(#<TweetsController>)> @message.errors.any?
=> true

「<% if @message.errors.any? %>」はこのようにtrueが返ったため「メッセージを入力してください。」が表示されるわけです。

erb
1
2
3
<% if @message.errors.any? %> # trueになるので下のコードが表示される
   <p class="red">メッセージを入力してください。</p>
<% end %>

メッセージが表示

redierct_toとの違い

成功したときに使っているredirect_toメソッドは実行するアクションを指定できるメソッドです。
上の例をみると成功したときにはredirect_toでルートのビューを表示させ、失敗したときにはrenderでnewアクションで返るビューを指定しています。

どちらも使用することにより表示するビューを指定することができるメソッドです。
ですが、なぜ失敗したときはrenderメソッドを使用しているのでしょうか?

前述した通り、redirect_toはHTTPリクエストを送り一度アクションを動かした後に同名のビューファイルをレンダリングします。
ですがrenderメソッドはHTTPリクエストを送らず、アクションを実行しないで指定したファイルをレンダリングするメソッドです。

今回失敗した場合もredirect_toを使ってしまうとどうなるでしょうか?

redirect_toの場合

1.newアクションが実行される
2.1回ビューファイルがリセットされる
3.newのビューファイルがレンダリングされる
4.newの見た目が表示される

このようにnewアクションを指定してしまうとnewアクションが実行された後にnewのビューファイルがレンダリングされます。

renderの場合

1.アクションを通さずにnewのビューファイルがレンダリングされる
2.入力された情報はそのまま
3.newの見た目が表示される

renderでレンダリングした場合は投稿フォームに入力していた情報はそのまま残っているので、レンダリング後のビューも同じ状態で表示されます。

2つを比較するとわかるように、1回アクションを実行してしまうと入力済みの情報が一度リセットされてしまうので、また入力しなくてはならなくなります。

入力した情報が多いときにはそのまま残っておいたほうがいいですよね?
なので失敗した際にはrenderメソッドを使って表示するビューを指定するようにしましょう。

renderメソッドを使うときの注意点

renderメソッドは同じアクションの中で2回以上呼び出されるとエラーになります。
下記のコードを見てみましょう。

ruby
1
2
3
4
5
6
7
def create
  message = Message.new(message_params)
  if message.save
    render :index
  end
  render :new
end

保存が成功したときはindexのビューをレンダリングするよう記述しました。
一見問題ないように見えますが、保存に成功した際はindexのビューがレンダリングされた後、newのビューもレンダリングしに行きます。
このとき「DoubleRenderError」というエラーが発生してしまいます。

このエラーを発生させないようにするには、下記のように「and return」を使います。

ruby
1
2
3
4
5
6
7
def create
  message = Message.new(message_params)
  if message.save
    render :index and return
  end
  render :new
end

改行をすればandは不要です。

ruby
1
2
3
4
5
6
7
8
def create
  message = Message.new(message_params)
  if message.save
    render :index
    return
  end
  render :new
end

同じアクション内でrenderを2回記述する場合は「and return」を使用するということを覚えておきましょう。

まとめ

・renderメソッドは呼び出すテンプレートファイルを指定できるメソッドです
・オプションを使うと様々な方法で呼び出すことができます