すでにメンバーの場合は

無料会員登録

GitHubアカウントで登録 Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

登録がまだの方はこちらから

Pikawakaにログイン

GitHubアカウントでログイン Pikawakaが許可なくTwitterやFacebookに投稿することはありません。

Rails

【Rails】layoutメソッドの使い方をマスターしよう!

ぴっかちゃん
ぴっかちゃん

layoutメソッドとは、コントローラーごとに各ページ共通のビューファイルを指定できるメソッドです。

コントローラー | 記述の仕方
1
layout 'ファイル名'
コントローラー | 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に記述したスタイルが適用されます。
application.html.erb内のyieldの部分にそれぞれのビューファイルが表示されます。

レイアウトファイルの仕組み

このようにyieldの部分には今回であれば下のindex.html.erbのコードが入り、上のように表示されたわけです。

index.html.erb

試しに<%= yield %>を削除してその部分に上のコードを入れてみても同じ結果になります。

コードの差し替え

このようにyieldの部分に各ページのコードが入るので差し替えても同じ結果になりました。
次に投稿フォームを表示するnew.html.erbを表示します。

レイアウトファイルの仕組み2

このように今回はnew.html.erbyieldに入り表示が変わりましたが、その他の部分はapplication.html.erbが表示されているのがわかります。

new.html.erb

index.html.erbは一覧画面なのでユーザーの一覧画面以外に年齢順の一覧が載っているサイドバーがあっても不自然ではありません。
ただ投稿フォームのページでサイドバーがあると不自然です。

ですので投稿フォームではサイドバーを取り除きたいですが、サイドバーはapplication.html.erbで読み込まれています。

application.html.erb

困りました、投稿フォームにはサイドバーを載せず投稿フォームを全画面で表示したいです。そんな時に便利なのがlayoutメソッドです。

今回はサイドバーがないレイアウトファイルのno_sidebar.html.erbを作成します。

no_sidebar.html.erb

そして下記のようにshowアクション内にlayoutメソッドを記述します。
※詳しい書き方は後述します

no_sidebar

すると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がこのコントローラーの全てのアクションで適用されます。

no_sidebar.html.erbがレイアウトファイル

さきほどとは表示が変わり、右カラムが表示されていないレイアウトが適用されているのが確認できます。

renderメソッドで指定

renderメソッドでアクションごとに共通するレイアウトを変更することができます。
この際アクション内に他のコードがある場合はアクションの最後の行に記述します。

コントローラー
1
2
3
def index
  render layout: 'ファイル名’ 
end

pikawakaを例にしてみます。
pikawakaではトップページの右カラムは最近の投稿が表示されています。

pikawakaトップページ

ですが記事のページでは右カラムは目次が表示されています。

記事ページ

記事ページは記事の詳細を表示するページなので、showアクションが動いています。showアクションだけ最近の投稿のサイドバーではなく、目次を表示したい場合は違ったレイアウトファイルを使うことができます。

post_content

アクションごとに使い分ける場合

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: [:アクション名, :アクション名, :アクション名]

layoutメソッドを使わない方法

/app/views/layoutsフォルダにコントローラーと同名のレイアウトファイルがあればこちらが優先して適用されます。

コントローラー | UsersContorollerの場合
1
2
3
4
class UsersController < ApplicationController
 def index
  end
end

このようにUsersControllerがあったとします。
そして/app/views/layouts/users.html.erbをレイアウトファイルとして作成します。

レイアウトファイルの結びつき

コードは下記のようにapplication.html.erbのコードに「users.html.erb」という文章を追加しました。

users.html.erb

そうするとlayoutメソッドを使わなくても自動でapplication.html.erbではなくusers.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が読み込まれるというわけです。

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の時のレイアウト
application.html.erbの時のレイアウト

admin.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

例をみていきましょう。

UsersControllerApplicationControllerを継承していいます。

UsersController

このときは下記のようにapplication.html.erbが適用されます。

application.html.erb

このコードが適用されて下記のように表示されます。

application.html.erbの時のレイアウト

それでは下記のようにApplicationController以外のコントローラーを継承しているときはどうなるでしょうか?

クラスの継承

AdminControlleradmin.html.erbを作成しているためレイアウトファイルはこちらが読み込まれます。

AdminViewsControllerAdminControllerを継承しています。
この時直前に継承したコントローラーの方が優先されるので、AdminViewsControllerのレイアウトファイルもadmin.html.erbが適用されるというわけです。

この場合、下記のadmin.html.erbが読み込まれます。

admin.html.erb

ですので、下記のようにadmin.html.erbのレイアウトが適用されます。

admin.html.erb

このように継承するコントローラーを変更することでレイアウトファイルを変更することもできます。

レイアウトファイルを変更

layoutsファイルでadmin_views.html.erbを作成すれば今度はこちらのレイアウトファイルが優先されます。

admin_views.html.erb

下の画像のようにadmin_views.html.erbが読み込まれるのが確認できます。

admin_views.html.erb

ポイント
  1. class UsersController < ApplicationControllerではControllerの前のUsersと同じusers.html.erbを作るとusers.html.erbが読み込まれます。
  2. class UsersController < ApplicationControllerとあれば、users.html.erbがなければ継承しているapplication.html.erbが読み込まれます。
  3. class AdminViewsController < AdminControllerとあれば、AdminControllerの様に継承するコントローラーを作ることで、admin.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にスタイルシートを呼び出す記述をしているためです。

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エラーが出たときのビューファイルを作成したとします。
レイアウトを無効にしない場合は下記のような画面になってしまいます。

404エラー

このときレイアウトファイルが適用されてしまわないように下記のように記述します。

コントローラー
1
2
3
def アクション名
  render "404.html", layout: false
end

renderメソッドでファイル名を指定すると表示するビューファイルを指定することができます。
このように記述するとレイアウトファイルが適用されず、今回は404.htmlを指定したので404.htmlに書かれた内容だけが表示されます。

レイアウトファイルが無効化

このようにレイアウトファイルが無効化されてすっきりしました。

この記事のまとめ

  • layoutメソッドは、コントローラーごとに共通のビューファイルを指定することができる
  • アクションごとに指定することも出来る
  • レイアウトファイルは必ず「layout」フォルダに作成しよう

8

わかった!