rails renderの基礎から使い方まで(partial, 引数)

Railsでサンプルコードを探していると、renderというメソッドをよく見かけます。

しかし、

・よく見るけど、renderってなに?
・ControllerとViewのどちらでも使えるけど、同じもの?
・オプションを指定するとJSONとかXMLを出力できるってホント?

など、様々な疑問が浮かんでくると思います。

そこで今回は、

・renderとは
・Controllerでrenderを使う方法
・Viewでrenderを使う方法
・renderの発展的な使い方として、JSONやXMLで出力する方法

について説明します。

それでは行ってみましょう!

目次

renderとは

renderは、レンダリング(rendering)という単語から名付けられたメソッドです。

renderの主な役割は、テンプレートを表示すること(=レンダリングすること)です。

MVCのControllerViewのどちらでも使用できますが、使い方には微妙な違いがあります。

また、renderには様々なオプションが用意されており、登録されたデータをJSONXMLで出力することもできます。

Ruby on Railsガイドの以下のページでもrenderについて触れていますので、もっと詳しく知りたい方はこちらも参考にしてください。

参考:https://railsguides.jp/action_view_overview.html

準備

renderの動作を確認するために、Ruby on Railsをインストールして、Railsサーバーを起動しておきましょう。

詳しくは、以下の記事で紹介していますので、ぜひご覧ください。

なお、今回の記事では、app/samurai/render-demoディレクトリにRailsをインストールしました。

Railsサーバーが起動できたら、いったんRailsサーバーを終了してから、次の手順を行います。

(1)以下のコマンドを1行ずつ順番に入力します。

bin/rails generate controller pages index help
bin/rails generate scaffold Post user_id:integer title:string month:integer
bin/rails db:migrate
bin/rails console

Controller(Pages Controller)とView(index View、help View)、Model(Posts Model)が作成され、Railsコンソールが起動します。

(2)以下のコードを1行ずつ順番に入力します。

Post.create(user_id:5,title:"楽しい休日の過ごし方" ,month:3)
Post.create(user_id:1,title:"先日の旅行での話" ,month:2)
Post.create(user_id:3,title:"昨日の出来事" ,month:12)
Post.create(user_id:3,title:"山登りに行きました" ,month:8)
Post.create(user_id:4,title:"友人が結婚しました" ,month:4)
Post.create(user_id:2,title:"最近少し気になったこと" ,month:1)
Post.create(user_id:4,title:"ランニングのコツ" ,month:9)
exit

Postテーブルに必要なデータが入力されました。

「http://localhost:3000/」にアクセスしたときに、app/views/pages/index.html.erbテンプレート(indexビュー)がレンダリング(表示)されるようにします。

(3)config/routes.rbを編集します。

変更前:

Rails.application.routes.draw do
  get 'pages/index'

  get 'pages/help'

  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end

変更後:

Rails.application.routes.draw do
  get 'pages/index'

  get 'pages/help'

  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
  root 'pages#index'
end

(4)以下のコマンドを入力します。

[code]
bin/rails server
[/code]

Railsサーバーが起動します。

これで準備完了です。

(5)ブラウザで「http://localhost:3000/」にアクセスしてみましょう。

以下のように、app/views/pages/index.html.erbテンプレートがレンダリング(表示)されていれば、次に進みましょう。

rails-render01

Controllerでテンプレートを使う

Controllerでは、他のアクションのテンプレートをそのまま利用する場合に、renderを使います。

「準備」でconfig/routes.rb(ルーター)を編集して、「http://localhost:3000/」にアクセスしたときに、Pages Controllerのindexアクションによって、app/views/pages/index.html.erbテンプレート(indexビュー)がレンダリング(表示)されるように変更しました。

rails-render01

今度は、app/controllers/pages_controller.rb(Pages Controller)のindexアクションでrenderを使い、indexビューの代わりに、app/views/pages/help.html.erbテンプレート(helpビュー)がレンダリング(表示)されるように変更します。

(1)app/controllers/pages_controller.rbを編集します。

変更前:

class PagesController < ApplicationController
  def index
  end

  def help
  end
end

変更後:

class PagesController < ApplicationController
  def index
    render "help"
  end

  def help
  end
end

(2)ブラウザで「http://localhost:3000/」にアクセスします。

URLは変わりませんが、以下のように、app/views/pages/help.html.erbテンプレート(help)がレンダリング(表示)されていますね。

rails-render02

(3)app/controllers/pages_controller.rbを元に戻します。

変更前:

class PagesController < ApplicationController
  def index
    render "help"
  end

  def help
  end
end

変更後:

class PagesController < ApplicationController
  def index
  end

  def help
  end
end

これで、再びapp/views/pages/index.html.erbテンプレート(index)が呼び出されるようになりました。

以上が、Controllerでのrenderの基本的な使い方です。

Controllerで部分テンプレートを使う

次に、Controllerで部分テンプレートと呼ばれるモノを使ってみましょう。

複数の投稿を1ページで表示する場合は、以下のように同じフォーマットを繰り返し適用しますね。

このような場合に、部分テンプレートを使います。

rails-render03

ただ、今回の例は、Controllerから部分テンプレートを無理矢理使っている感じになりました。

部分テンプレートを使うのはViewのほうが良さそうです。

(1)app/views/pages/_post.html.erbを以下の内容で作成します。

<%= post.title %>

ユーザーID:<%= post.user_id %>

投稿月:<%= post.month %>

このファイルが部分テンプレートです。

部分テンプレートのファイル名は、必ず_(アンダーバー)で始めます。

(2)app/controllers/pages_controller.rbを編集します。

変更前:

class PagesController < ApplicationController
  def index
  end

  def help
  end
end

変更後:

class PagesController < ApplicationController
  def index
    render :partial => "post.html.erb", :collection => Post.all
  end

  def help
  end
end

(3)ブラウザで「http://localhost:3000/」にアクセスします。

手順の前に紹介したように、app/views/pages/_post.html.erbテンプレートがPostの数だけレンダリング(表示)されていることを確認してください。

変数を渡す

Controllerで部分テンプレートをレンダリングするときは、「:collection => Post.all」という書きかたでPostテーブルのデータを渡しています。

ここではさらに、モデルとは無関係のローカル変数を渡す方法を紹介します。

(1)app/views/pages/_post.html.erbを以下の内容に変更します。

変更前:

<%= post.title %>

ユーザーID:<%= post.user_id %>

投稿月:<%= post.month %>

変更後:

<%= post.title %>

ユーザーID:<%= post.user_id %>

投稿月:<%= post.month %>

「#90ee90」を「<%= bgcolor %>」に変更しました。

ここに変数bgcolorの値が入ることになります。

(2)app/controllers/pages_controller.rbを編集します。

変更前:

class PagesController < ApplicationController
  def index
  end

  def help
  end
end

変更後:

class PagesController < ApplicationController
  def index
    render :partial => "post.html.erb", :collection => Post.all, :locals => { :bgcolor => "#ffe6e6" }
  end

  def help
  end
end

「:locals => { :bgcolor => "#ffe6e6" }」で、変数bgcolor(値は”#ffe6e6”)を渡しています。

(3)ブラウザで「http://localhost:3000/」にアクセスします。

以下のように、色が変わりますね。

rails-render04

「#ffe6e6」を「lightsteelblue」に変更しても色を変えられます。

この後、Viewで部分テンプレートを使う方法を説明するために、app/controllers/pages_controller.rbを次のように戻しておきましょう。

(4)app/controllers/pages_controller.rbを編集します。

変更前:

class PagesController < ApplicationController
  def index
    render :partial => "post.html.erb", :collection => Post.all, :locals => { :bgcolor => "#ffe6e6" }
  end

  def help
  end
end

変更後:

class PagesController < ApplicationController
  def index
  end

  def help
  end
end

これで、「http://localhost:3000/」にアクセスしたときの表示が元に戻りました。

Viewで部分テンプレートを使う

ヘッダーやフッター、メニューなど、複数のページで共通の内容を表示するためには、Viewでrenderを使って部分テンプレートを呼び出します。

今回は、app/views/pages/index.html.erbテンプレート(indexビュー)にヘッダーとフッターを追加してみましょう。

各ファイル名は、以下のようにします。

項目ファイル名
ヘッダーapp/views/pages/_header.html.erb
フッターapp/views/pages/_footer.html.erb

(1)app/views/pages/_header.html.erbを以下の内容で作成します。

☆ヘッダー☆

(2)app/views/pages/_footer.html.erbを以下の内容で作成します。

★フッター★

(3)app/views/pages/index.html.erbを編集します。

変更前:

Pages#index

Find me in app/views/pages/index.html.erb

変更後:

<%= render 'header'%>

Pages#index

Find me in app/views/pages/index.html.erb

<%= render 'footer'%>

(4)ブラウザで「http://localhost:3000/」にアクセスします。

以下のように、「☆ヘッダー☆」や「★フッター★」が表示されていますね。

rails-render05

Viewでもrenderを使って、部分テンプレートを呼び出せましたね。

変数を渡す

Viewで部分テンプレートを使う場合も、Controllerで部分テンプレートを使う場合と同じように変数を渡せます。

先ほど作成した_post.html.erbをそのまま利用して、ViewでもPostテーブルのデータと、モデルと無関係のローカル変数を渡せることを確認しましょう。

(1)app/views/pages/index.html.erbを編集します。

変更前:

<%= render 'header'%>

Pages#index

Find me in app/views/pages/index.html.erb

<%= render 'footer'%>

変更後:

<%= render 'header'%>

Pages#index

Find me in app/views/pages/index.html.erb

<% @posts.each do |post| %> <%= render partial: "post", :locals => {:bgcolor => "lightsteelblue", :post => post} %> <% end %> <%= render 'footer'%>

(2)app/controllers/pages_controller.rbを編集します。

変更前:

class PagesController < ApplicationController
  def index
  end

  def help
  end
end

変更後:

class PagesController < ApplicationController
  def index
    @posts = Post.all
  end

  def help
  end
end

このように書くと、app/views/pages/index.html.erb(indexビュー)で必要な「@posts」をControllerから渡せます。

(3)ブラウザで「http://localhost:3000/」にアクセスします。

rails-render06

先ほどの例から色が変わっただけでなく、ヘッダーやフッターも付いたままですね!

JSONやXMLを返す

renderは、さまざまな方式でデータを出力できますので、その一例としてJSONやXMLを出力する方法も紹介しましょう。

今度はPosts Controllerを編集していますので、注意してくださいね!

(1)app/controllers/posts_controller.rbを以下のように編集します。

変更前:

class PostsController < ApplicationController
  before_action :set_post, only: [:show, :edit, :update, :destroy]

  # GET /posts
  # GET /posts.json
  def index
    @posts = Post.all
  end
(省略)

変更後:

class PostsController < ApplicationController
  before_action :set_post, only: [:show, :edit, :update, :destroy]

  # GET /posts
  # GET /posts.json
  def index
    @posts = Post.all
    respond_to do |format|
      format.html
      format.json {render :json => @posts}
      format.xml  {render :xml => @posts}
    end
  end
(省略)

(2)ブラウザで「http://localhost:3000/posts.json」にアクセスします。

以下のように表示されます。

rails-render07

これは読みにくいので、整形すると以下のようになります。

[
    {
        "id": 1,
        "user_id": 5,
        "title": "楽しい休日の過ごし方",
        "month": 3,
        "created_at": "2018-06-22T06:38:30.335Z",
        "updated_at": "2018-06-22T06:38:30.335Z"
    },
    {
        "id": 2,
        "user_id": 1,
        "title": "先日の旅行での話",
        "month": 2,
        "created_at": "2018-06-22T06:38:30.405Z",
        "updated_at": "2018-06-22T06:38:30.405Z"
    },
    (省略)
]

(3)続けてブラウザで「http://localhost:3000/posts.xml」にアクセスします。

以下のように表示されます。

rails-render08

確かにXMLではありますので文句は言えませんが、コレジャナイ感が半端ないです。

JSONと同じようなXMLを出力するには、activemodel-serializers-xmlが必要でした。

(4)Gemfileの最終行に以下の内容を追加します。

gem 'activemodel-serializers-xml'

(5)Railsサーバーを起動した端末でCtrlキーを押しながらCキーを押し、以下のコマンドを入力します。

bundle install

(6)gemをインストールしたら、以下のコマンドを入力します。

bin/rails server

Railsサーバーが起動します。

(7)もう一度ブラウザで「http://localhost:3000/posts.xml」にアクセスします。

rails-render09

これだ!

実は、app/controllers/posts_controller.rbを変更しなくても、JSONだけなら表示できます。

ただ、JSONだけでなくXMLも出力するなら、この手順で説明したようにposts_controller.rbを編集します。

まとめ

今回はRailsのrenderについて解説していきました。

ControllerでもViewでも、renderを使って部分テンプレートを使ったり、変数を使って値を渡したりできました。

renderは、さまざまな方式でデータを出力できますので、その一例としてJSONXMLを出力する方法も確認しました。

Viewに同じようなHTMLを書くことになったら、renderで(主観的ですが)キレイにまとめることを検討します。

しかし、複雑なコードを書いてようやくまとめられる!というレベルのときは、Viewのコードをキレイにすることを目指して、Controllerでrenderを使うことも検討しましょう。

ControllerでもViewでも書けるのは便利な反面、役割分担がないがしろにされる一因にもなってしまいますので、十分に検討して、動作を追いかけやすいコードを書くように注意してください。

それでは!

この記事を書いた人

侍エンジニア塾は「人生を変えるプログラミング学習」をコンセンプトに、過去多くのフリーランスエンジニアを輩出したプログラミングスクールです。侍テック編集部では技術系コンテンツを中心に有用な情報を発信していきます。

目次