更新日:
【Rails】 layoutメソッドの使い方と使い所とは?
layoutメソッドとは、コントローラーごとに各ページ共通のビューファイルを指定できるメソッドです。
1
layout 'ファイル名'
1
2
3
4
5
6
7
8
class コントローラ名 < ApplicationController
# layoutを指定した場合、layouts/application.html.erbではなくlayouts/top.html.erbが読み込まれる
layout 'top'
def アクション名
end
end
layoutメソッドに指定するファイルは、/app/views/layoutsフォルダ
に作成します。
layoutメソッドの使い方
この章では、layoutメソッドの使い方について解説します。
実際どういう時に使うか?
では一体どういう時にlayoutメソッド
を使うのでしょうか?
layoutメソッドを使用しない場合
layoutメソッド
でレイアウトファイルを指定しなかった場合はapplication.html.erb
が使われます。
ヘッダーやフッターなど、各ページ共通の部分は基本的なレイアウトファイルであるapplication.html.erb
に記述しています。
このように各ページ共通のビューファイルのことをレイアウトファイルと呼びます。
レイアウトファイルはアクセスされた時に最初に読み込まれます。
この時は下記のようにapplication.html.erb
に記述したスタイルが適用されます。
application.html.erb
内のyield
の部分にそれぞれのビューファイルが表示されます。
このようにyield
の部分には今回であれば下のindex.html.erb
のコードが入り、上のように表示されたわけです。
試しに<%= yield %>
を削除してその部分に上のコードを入れてみても同じ結果になります。
このようにyieldの部分に各ページのコードが入るので差し替えても同じ結果になりました。
次に投稿フォームを表示するnew.html.erbを表示します。
このように今回はnew.html.erb
がyield
に入り表示が変わりましたが、その他の部分はapplication.html.erb
が表示されているのがわかります。
index.html.erbは一覧画面なのでユーザーの一覧画面以外に年齢順の一覧が載っているサイドバーがあっても不自然ではありません。
ただ投稿フォームのページでサイドバーがあると不自然です。
ですので投稿フォームではサイドバーを取り除きたいですが、サイドバーはapplication.html.erbで読み込まれています。
困りました、投稿フォームにはサイドバーを載せず投稿フォームを全画面で表示したいです。そんな時に便利なのがlayoutメソッド
です。
今回はサイドバーがないレイアウトファイルのno_sidebar.html.erb
を作成します。
そして下記のようにshowアクション内にlayoutメソッドを記述します。
※詳しい書き方は後述します
するとnewアクションのビューだけno_sidebar.html.erb
が使われ、application.html.erb
のときに表示されていた右カラム(年齢順のユーザー情報)が表示されないスタイルが適用されます。
このような時に使うのがlayoutメソッド
です。
layoutメソッドを使用した場合
layoutメソッド
を使用すると記述したコントローラーの全てのアクションのビューでapplication.html.erb
に書いたような共通のレイアウトを指定することができます。
layoutメソッドを使うにはまず/app/views/layoutsフォルダ
にレイアウトファイルを作成します。
今回はno_sidebar.html.erbファイル
をレイアウトファイルとして作成します。
このレイアウトファイルでは右カラムを表示させたくないので、application.html.erb
で記述していた右カラムを削除したコードを記述します。
そして下記のようにレイアウトファイルとしてno_sidebar.html.erb
を指定します。
上の例だとレイアウトファイルとしてno_sidebar.html.erb
がこのコントローラーの全てのアクションで適用されます。
さきほどとは表示が変わり、右カラムが表示されていないレイアウトが適用されているのが確認できます。
renderメソッドで指定
renderメソッド
でアクションごとに共通するレイアウトを変更することができます。
この際アクション内に他のコードがある場合はアクションの最後の行に記述します。
1
2
3
def index
render layout: 'ファイル名’
end
pikawakaを例にしてみます。
pikawakaではトップページの右カラムは最近の投稿が表示されています。
ですが記事のページでは右カラムは目次が表示されています。
記事ページは記事の詳細を表示するページなので、showアクションが動いています。showアクションだけ最近の投稿のサイドバーではなく、目次を表示したい場合は違ったレイアウトファイルを使うことができます。
アクションごとに使い分ける場合
layoutメソッド
だけでアクションごとに使い分けることも可能です。
その際は下記のように記述します。
1
2
3
4
layout 'ファイル名', only: :アクション名
# newアクションだけ指定
layout 'ファイル名', only: :new
onlyオプション
オプションでonlyを使うと適用させるアクションを指定することができます。
1
2
3
4
5
6
7
8
9
layout 'ファイル名', only: :アクション名
# newアクションだけ指定
layout 'ファイル名', only: :new
# 上のコードは下記のコードと同じ
def new
render layout: “ファイル名”
end
exceptオプション
オプションでexceptを使うと適用させないアクションを指定することができます。
例えばアクションがindexとnewの2つしかない場合下記のように記述したとします。
1
layout 'ファイル名', except: :index
上のコードだとexceptは除外するという意味なので、indexを外したらnewだけに適用されるため上のコードと同義になります。
ただ可読性を考えるとexceptはあまり使わないので、onlyを使う様にしましょう。
showアクションだけでなく、newアクション、editアクションの3つだけ違うレイアウトを使用したいときはそれぞれのアクション内にrenderメソッドを使っての記述をするのは面倒です。
その際は下記のようにまとめて指定することができます。
上のように記述するとnew・editアクション以外はapplication.html.erb
が、new・editアクションのときはtop.html.erb
が読み込まれます。
このように複数のアクションを指定したい場合は配列を使います。
1
layout 'ファイル名', only: [:アクション名, :アクション名, :アクション名]
Ruby on Railsについて一通り学びたい方は、こちらの参考書もよく使われていますよ!
layoutメソッドを使わない方法
/app/views/layoutsフォルダ
にコントローラーと同名のレイアウトファイルがあればこちらが優先して適用されます。
1
2
3
4
class UsersController < ApplicationController
def index
end
end
このようにUsersController
があったとします。
そして/app/views/layouts/users.html.erb
をレイアウトファイルとして作成します。
コードは下記のようにapplication.html.erb
のコードに「users.html.erb」という文章を追加しました。
そうするとlayoutメソッドを使わなくても自動でapplication.html.erb
ではなくusers.html.erb
がレイアウトファイルとして適用されます。
このようにusers.html.erb
がレイアウトファイルとして適用されました。
では間違えてuser.html.erb
という名前で作成するとどうなるでしょうか?
すると上の動画のようにusers.html.erb
は存在しないのでapplication.html.erb
が読み込まれるのを確認できます。
このようにコントローラー名と同じファイル名にしないとlayoutファイルは読み込まれませんので注意しましょう。
application.html.erbが読み込まれる理由
ではそもそもどうしてデフォルトだとapplication.html.erb
が読み込まれるのでしょうか?
それは全てのコントローラーはデフォルトでApplicationController
を継承している状態で作成されるからです。
1
2
3
4
# ApplicationControllerを継承している
class HogesController < ApplicationController
def show; end
end
コントローラー名と同じレイアウトファイルが自動で読み込まれるので、ApplicationController
の場合はapplication.html.erb
が読み込まれるというわけです。
先程の例ではUsersController
でなぜ最初はapplication.html.erb
が読み込まれていたかというと、users.html.erb
がなかったからです。
もしusers.html.erb
があれば説明した様にusers.html.erb
が読み込まれ、users.html.erb
がなければ継承していたapplication.html.erb
が読み込まれます。
まとめると今までデフォルトでapplication.html.erb
が読み込まれてた理由は全てのコントローラーでApplicationController
が継承されていているのでlayoutsフォルダにあるapplication.html.erb
が読み込まれていたというわけです。
実際に使う時は?
例えばアプリの管理画面を作成するためAdminController
を作ったとします。
管理画面なので管理画面用のレイアウトを当てたいですよね?
そんな時layoutsフォルダにadmin.html.erb
を作ってあげるとAdminControllerのビューファイルの全てのレイアウトがadmin.html.erb
になります。
application.html.erbの時のレイアウト
admin.html.erbの時のレイアウト
このように全く違うデザインにしたい時などに便利です。
クラスの継承でレイアウトファイルを指定
もし上の例のようにadmin系のコントローラーを別に作り、そこでもAdminController
のレイアウトを使いたい場合は継承するコントローラーをApplicationController
からAdminController
に変更するとAdminController
と同じレイアウトが適用されます。
1
2
3
4
5
6
7
8
9
# ApplicationControllerを継承しているのでapplication.html.erbが適用
class AdminViewsController < ApplicationController
def show; end
end
# AdminControllerを継承しているのでadmin.html.erbが適用
class AdminViewsController < AdminController
def show; end
end
例をみていきましょう。
UsersController
はApplicationController
を継承していいます。
このときは下記のようにapplication.html.erb
が適用されます。
このコードが適用されて下記のように表示されます。
それでは下記のようにApplicationController
以外のコントローラーを継承しているときはどうなるでしょうか?
AdminController
はadmin.html.erb
を作成しているためレイアウトファイルはこちらが読み込まれます。
AdminViewsController
はAdminController
を継承しています。
この時直前に継承したコントローラーの方が優先されるので、AdminViewsController
のレイアウトファイルもadmin.html.erb
が適用されるというわけです。
この場合、下記のadmin.html.erb
が読み込まれます。
ですので、下記のようにadmin.html.erb
のレイアウトが適用されます。
このように継承するコントローラーを変更することでレイアウトファイルを変更することもできます。
layoutsファイルでadmin_views.html.erb
を作成すれば今度はこちらのレイアウトファイルが優先されます。
下の画像のようにadmin_views.html.erb
が読み込まれるのが確認できます。
layoutを無効にする方法
layoutメソッド
を使用しない場合は自動でapplication.html.erb
が適用されます。
全てのレイアウトを無効にするにはlayout false
と記述します。
1
2
3
4
5
6
7
class コントローラ名 < ApplicationController
layout false # この記述によりレイアウトファイルは読み込まれない
def アクション名
end
end
指定したアクションだけレイアウトを無効にしたい時があります。
その際は下記のように記述するとそのアクションだけ全ての共通のレイアウトが無効になります。
1
2
3
def アクション名
render layout: false
end
例えばindexアクションだけレイアウトファイルを無効にしたいときは下記のように記述します。
1
2
3
def index
render layout: false
end
するとindexアクションが動いたときは下記のようにレイアウトファイルが適用されない表示になります。
スタイルシートが適用されていないのは今回無効化したapplication.html.erb
にスタイルシートを呼び出す記述をしているためです。
1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html>
<head>
<title>ProgramanDojo</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
# application.html.erbが読み込まれないので、↓のスタイルシートが読み込まれない
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
では実際どういったときにレイアウトファイルを無効化するのでしょうか?
例えば404エラーが出たときのビューファイルを作成したとします。
レイアウトを無効にしない場合は下記のような画面になってしまいます。
このときレイアウトファイルが適用されてしまわないように下記のように記述します。
1
2
3
def アクション名
render "404.html", layout: false
end
renderメソッドでファイル名を指定すると表示するビューファイルを指定することができます。
このように記述するとレイアウトファイルが適用されず、今回は404.htmlを指定したので404.htmlに書かれた内容だけが表示されます。
このようにレイアウトファイルが無効化されてすっきりしました。
この記事のまとめ
- layoutメソッドは、コントローラーごとに共通のビューファイルを指定することができる
- アクションごとに指定することも出来る
- レイアウトファイルは必ず「layout」フォルダに作成しよう