更新日:
【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」フォルダに作成しよう