Help us understand the problem. What is going on with this article?

【Rails 部分テンプレート(render partial)を用いたviewを別コントローラから呼び出す(render template)】

はじめに

業務にて、コントローラ(1)のアクションAでview(a)を表示するためにrenderを使い、別コントローラ(2)のアクションBで呼び出されるview(b)を呼び出した。しかし、view(b)は部分テンプレートを使っておりview(a)が上手く表示されない……という事態に。
解決できたのでメモしておきます。

[前提1] コントローラ内で使う renderメソッド

renderメソッドは、コントローラのアクション内で呼び出すview(テンプレート)を指定します。
他に使われることの多いredirect_toは、指定したURLへ直接リダイレクトされます。

renderメソッドにはオプションが複数あります。

同一コントローラ内の他のアクションに対応するviewを呼び出す場合 [render action]
admin_controller.rb
#app/views/admin/edit.html.erbを呼び出す
def update
  if @post.save
    redirect_to('/admin/index')
  else
    render action: :edit
end
レイアウトを指定して呼び出す場合[render layout]
admin_controller.rb
#app/views/layouts/hoge.html.erbをレイアウトとして呼び出す
def edit
  @article = Posts.find_by(id: params[:id])
  render layout: 'hoge'
end
別のコントローラーのアクションに対応するviewを呼び出す場合[render template: 'コントローラ名/アクション名']
admin_controller.rb
#app/views/home/indexを呼び出し、app/views/layouts/hoge.html.erbをレイアウトとして呼び出す
def preview
  render template: 'home/index', layout: 'hoge'
end

本題では3つ目のrender templateを使います。

他にもjsonを返すrender jsonや、アプリケーション外のテンプレートを表示するrender fileなどがあります。(http://railsdoc.com/references/render)

[前提2] 部分テンプレート viewで用いるrender partial

viewで繰り返し表示するパーツや、共通のパーツは部分テンプレートにまとめることができます。
ここではpostモデルにtitleカラムを持つものとします。

app/views/home/index.html.erb
<div>
<%@posts.each do |post|%>
...
  <div>
  <%= render partial: "title", locals: { title: post.title }%>
  </div>
...
<%end%>
</div>
app/views/home/_title.html.erb
<p>タイトルは<%=title %>です</p>

view内での書き方は、
render partial: "呼び出すファイル名", locals:{ local変数(呼び出すファイル内で用いる変数名): 渡す値 }です。

[本題] 部分テンプレート(render partial)を用いたviewを別コントローラから呼び出したい

ここからが本題です。
[前提1]の3つ目の例と[前提2]の2つのファイルを使います。

・コントローラ

admin_controller.rb
#app/views/home/indexを呼び出し、app/views/layouts/hoge.html.erbをレイアウトとして呼び出す
def preview
  render template: 'home/index', layout: 'hoge'
end

・呼び出すview(テンプレート)

app/views/home/index.html.erb
<div>
<%@posts.each do |post|%>
...
  <div>
  <%= render partial: "title", locals: { title: post.title }%>
  </div>
...
<%end%>
</div>

まずは、admin_controllerのpreviewアクションに対応するviewを作ります。

app/views/admin/preview.html.erb
#app/views/home/index.erbがテンプレートとして入ります。何も記入しなくてOKです。

これだけだと、'title'というviewが見つからないとエラーが出てしまいました・・・。
コントローラにrender partial: 'home/titleを追加してみるもエラー。

試しに、app/views/admin/_title.html.erbというファイルを作ってみると、エラーは解消されたが何も表示されず。

中身を表示させてしまえば良いのかと思い、ここでも部分テンプレートを使ってみることに。

app/views/admin/_title.html.erb
<%= render partial: "home/title", locals: { title: post.title }%>

これで無事に内容が表示されました。
別コントローラの部分テンプレートを用いる際はrender partial "コントローラ名/ファイル名"で良さそうです。
"home/_title"では上手くいきませんでしたのでアンダーバーは不要…。

まとめ

部分テンプレート(render partial)を用いたviewを別コントローラから呼び出す際は、
1.アクションに対応するviewファイルを作る
2.呼び出すviewの部分テンプレートと同名のviewファイルを作る
3.2で作ったファイルで、元の部分テンプレートを呼び出す

終わりに

render templateしたら、呼び出した先の部分テンプレートも連れてきてくれるものだと勝手に思っていたので勉強になりました。
初心者ですので、間違っている点や他の方法等あればご指摘いただけますと幸いです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away