##はじめに
業務にて、コントローラ(1)のアクションAでview(a)を表示するためにrenderを使い、別コントローラ(2)のアクションBで呼び出されるview(b)を呼び出した。しかし、view(b)は部分テンプレートを使っておりview(a)が上手く表示されない……という事態に。
解決できたのでメモしておきます。
##[前提1] コントローラ内で使う renderメソッド
renderメソッドは、コントローラのアクション内で呼び出すview(テンプレート)を指定します。
他に使われることの多いredirect_toは、指定したURLへ直接リダイレクトされます。
renderメソッドにはオプションが複数あります。
#####同一コントローラ内の他のアクションに対応するviewを呼び出す場合 [render action]
#app/views/admin/edit.html.erbを呼び出す
def update
if @post.save
redirect_to('/admin/index')
else
render action: :edit
end
#####レイアウトを指定して呼び出す場合[render layout]
#app/views/layouts/hoge.html.erbをレイアウトとして呼び出す
def edit
@article = Posts.find_by(id: params[:id])
render layout: 'hoge'
end
#####別のコントローラーのアクションに対応するviewを呼び出す場合[render template: 'コントローラ名/アクション名']
#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カラムを持つものとします。
<div>
<%@posts.each do |post|%>
...
<div>
<%= render partial: "title", locals: { title: post.title }%>
</div>
...
<%end%>
</div>
<p>タイトルは<%=title %>です</p>
view内での書き方は、
render partial: "呼び出すファイル名", locals:{ local変数(呼び出すファイル内で用いる変数名): 渡す値 }
です。
##[本題] 部分テンプレート(render partial)を用いたviewを別コントローラから呼び出したい
ここからが本題です。
[前提1]の3つ目の例と[前提2]の2つのファイルを使います。
・コントローラ
#app/views/home/indexを呼び出し、app/views/layouts/hoge.html.erbをレイアウトとして呼び出す
def preview
render template: 'home/index', layout: 'hoge'
end
・呼び出すview(テンプレート)
<div>
<%@posts.each do |post|%>
...
<div>
<%= render partial: "title", locals: { title: post.title }%>
</div>
...
<%end%>
</div>
まずは、admin_controllerのpreviewアクションに対応するviewを作ります。
#app/views/home/index.erbがテンプレートとして入ります。何も記入しなくてOKです。
これだけだと、'title'というviewが見つからないとエラーが出てしまいました・・・。
コントローラにrender partial: 'home/title
を追加してみるもエラー。
試しに、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したら、呼び出した先の部分テンプレートも連れてきてくれるものだと勝手に思っていたので勉強になりました。
初心者ですので、間違っている点や他の方法等あればご指摘いただけますと幸いです。