「Ruby on Rails6 実践ガイド」を読むシリーズの続きです。
今日はChapter5の前半、レイアウトとかテンプレートの話です。
- 環境:macOS Catalina / Ruby 2.7.1 / Rails 6.0.3 / Chrome / PostgreSQL 13.1
トップページ(仮)の作成
Baukis2の利用者別トップページを作成していきます。
ルーティングの設定
とりあえず、利用者ごとに以下のURLでアクセスできるようにする。
まずはroutes.rbを開いて、それぞれに名前空間を設定するnamespaceというメソッドを使用してルーティングを設定する。(ルーティングの詳細は別の章で)
# config/routes.rb Rails.application.routes.draw do namespace :staff do root 'top#index' end namespace :admin do root 'top#index' end namespace :customer do root 'top#index' end end
この結果、URLパスの先頭に含まれる文字列(staff/admin/customer)が特別な意味を持つようになる。
rootは、クライアント(ブラウザ)がルートURLにアクセスしたときに、どのアクションが処理を受け持つかを指定するメソッド。
root 'top#index'
root 'コントローラー名#アクション名'
で記述されている。
コントローラーとアクションの作成
config/routes.rbで指定した3つのコントローラーを生成する。
% bin/rails g controller staff/top Running via Spring preloader in process 1696 create app/controllers/staff/top_controller.rb invoke erb create app/views/staff/top invoke rspec create spec/requests/staff/top_request_spec.rb
同様に他の2つも生成。
% bin/rails g controller admin/top % bin/rails g controller customer/top
生成された3つのコントローラーについて、indexアクションを追加する。
# app/controllers/staff/top_controller.rb class Staff::TopController < ApplicationController def index render action: 'index' end end
Rails用語のアクションとは、コントローラークラスのpublicなインスタンスメソッドを指す。
render action: 'index'
renderは、HTML文書を生成するメソッドである。この式は、標準パスにあるindexアクション用のERBテンプレート(app/views/staff/top/index.html.erb)を用いてHTML文書を作成せよ、という意味になる。
ERBテンプレートとはRubyを埋め込む仕組みのことで、ERBテンプレートのファイルには.erbという拡張子をつける。結果としてHTMLが作成されるのであれば、.html.erbのように二重に拡張子をつけるのが一般的。
原則としてERBテンプレートはapp/viewsディレクトリにコントローラーごとにわけて置き、ファイル名にはアクション名を使う。
なお、アクションの中で一度もクライアント(ブラウザ)にレスポンスを返すメソッド(render、redirect_to、send_file、respond_withなど)が呼ばれなかった場合、暗黙的にそのアクションに対応するERBテンプレートを用いてHTML文書が生成される。つまり、先ほどのrender action: 'index'
という行は省略することができ、indexアクションは以下のように中身がなくても良い。
def index end
ERBテンプレートの作成
app/views/staff/topディレクトリに新たにindex.html.erbを作成する。
# app/views/staff/top/index.html.erb <% @title = '職員トップページ' %> <h1><%= @title %></h1>
<%
と%>
で囲まれた範囲はRubyコードとして解釈される。
ブラウザでhttp://localhost:3000/staffにアクセスすると、画面が表示されればOK。
% bin/rails db:create
しないとDBがありませんってエラーが出るはず。
同様に、app/views/admin/top/index.html.erbとapp/views/customer/top/index.html.erbも作成し、管理者トップページと顧客トップページを表示させる。
レイアウト
作成したトップページのソースコードを確認すると、bodyタグやhtmlタグなどのERBテンプレートに記述した以外のことも含まれている。
これらはapp/views/layoutsディレクトリにあるERBテンプレートからきている。このERBテンプレートをレイアウトと呼ぶ。
デフォルトではapp/views/layoutsにapplication.html.erbというファイルがあるだけで、内容は次の通り。
# app/views/layouts/application.html.erb <!DOCTYPE html> <html> <head> <title>Baukis2</title> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %> </head> <body> <%= yield %> </body> </html>
<%= yield %>
という部分にアクションで指定されたERBテンプレートが挿入され、レイアウトを含むHTML文書全体がブラウザに返されるようになっている。
また、stylesheet_link_tagはこのページに読み込むCSSファイルを指定するメソッドで、第1引数にはCSSファイルの名前を指定する。stylesheet_link_tag 'application'
はapp/assets/stylesheetsディレクトリにあるapplication.cssが読み込まれることになる。
部分テンプレート
application.html.erbを次のようにカスタマイズする。
# app/views/layouts/application.html.erb : <body> <div id='wrapper'> <%= render 'shared/header' %> <div id='container'> <%= yield %> </div> <%= render 'shared/footer' %> </div> </body> </html>
そして、app/viewディレクトリにsharedディレクトリを作成し、新規ファイル_header.html.erbを次の内容で作成する。
# app/views/shared/_header.html.erb <header> <span class='logo-mark'>BAUKIS2</span> </header>
さらに、app/views/sharedディレクトリに新規ファイル_footer.html.erbを作成し、以下の内容を記述する。
# app/views/shared/_footer.html.erb <footer> <p>© 2020 Tsutomu Kuroda</p> </footer>
ブラウザで確認すると、このように変化する。
レイアウトに加えた
<%= render 'shared/header' %>
と
<%= render 'shared/footer' %>
は、いずれもrenderメソッドによって部分テンプレートをレイアウトの中に埋め込んでいる。
部分テンプレートとは、他のERBテンプレートに埋め込まれるためのERBテンプレートで、ファイル名がアンダースコア(_)で始まるという規則がある。
ヘルパーメソッドの定義
ERBテンプレート(レイアウト、部分テンプレートも含む)の中で使用できるメソッドをヘルパーメソッドと呼ぶ。
ヘルパーメソッドは自分で定義することもできる。app/helperディレクトリにあるapplication_helper.rbでApplicationHelperのモジュールメソッドとして定義すればヘルパーメソッドになる。
次のように変更して、簡単なメソッドを作成してみよう。
# app/helpers/application_helper.rb module ApplicationHelper def document_title if @title.present? "#{@title} - Baukis2" else 'Baukis2' end end end
レイアウトも変更する。
# app/views/layouts/application.html.erb : <html> <head> <title><%= document_title %></title> # 変更 <%= csrf_meta_tags %> <%= csp_meta_tag %> : :
ブラウザをリロードすると、タイトルバーに表示されているテキストが変わる。
感想
今回の内容自体は難しくなかったが、作業しているとDBに接続できなかったりエラーが起きた。 時間はかかったし最適解じゃないかもしれないけど、解決できて無事に動作確認ができたのがうれしかった。