見出し画像

Ruby on Rails6習得編 Ruby on Rails 6 実践ガイド Chapter5 ビジュアルデザイン

こちらの書籍について学んだことです。

Chapter5 ビジュアルデザイン

ビジュルアル面の基礎的な知識について学ぶ

5.1 仮設トップページの作成

仮設トップページを作成する。

5.1.1 ルーティングの設定

いったん下記でトップページにアクセスしてみる

職員 http://localhost:3000/staff
管理者 http://localhost:3000/admin
顧客 http://localhost:3000/customer

エディタでconfig/routes.rbを開く

最初は下記のようになっている。

config/routes.rb
----------------------------------------
Rails.application.routes.draw do
end
----------------------------------------

これを次のように変更する

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

詳細は9章で説明

topはコントローラ名
indexはアクション名

5.1.2 コントローラとアクションの作成

次のコマンドを実行
bin/rails g controller staff/top
bin/rails g controller admin/top
bin/rails g controller customer/top

----------------------------------------
bash-4.4$ bin/rails g controller staff/top
Running via Spring preloader in process 72
     create  app/controllers/staff/top_controller.rb
     invoke  erb
     create    app/views/staff/top
     invoke  rspec
bash-4.4$ bin/rails g controller admin/top
Running via Spring preloader in process 77
     create  app/controllers/admin/top_controller.rb
     invoke  erb
     create    app/views/admin/top
     invoke  rspec
bash-4.4$ bin/rails g controller customer/top
Running via Spring preloader in process 85
     create  app/controllers/customer/top_controller.rb
     invoke  erb
     create    app/views/customer/top
     invoke  rspec
bash-4.4$ 
----------------------------------------

下記のファイルが作成された
app/controllers/staff/top_controller.rb
app/controllers/admin/top_controller.rb
app/controllers/customer/top_controller.rb
そして下記のディレクトリも作成された
app/views/staff/top
app/views/admin/top
app/views/customer/top

rails g controllerでコントローラファイルとビューファイルが作られるのね!

生成された3つのコントローラの生成直後は以下のようになっている。

app/controllers/staff/top_controller.rb修正前
----------------------------------------
class Staff::TopController < ApplicationController
end
----------------------------------------
app/controllers/admin/top_controller.rb修正前
----------------------------------------
class Admin::TopController < ApplicationController
end
----------------------------------------
app/controllers/customer/top_controller.rb修正前
----------------------------------------
class Customer::TopController < ApplicationController
end
----------------------------------------

次のように、生成された3つのコントローラにindexアクションを追加していく。

app/controllers/staff/top_controller.rb修正後
----------------------------------------
class Staff::TopController < ApplicationController
 def index
   render action: "index"
 end
end
----------------------------------------
app/controllers/admin/top_controller.rb修正後
----------------------------------------
class Admin::TopController < ApplicationController
 def index
   render action: "index"
 end
end
----------------------------------------
app/controllers/customer/top_controller.rb修正後
----------------------------------------
class Customer::TopController < ApplicationController
 def index
   render action: "index"
 end
end
----------------------------------------

indexアクションは、それぞれのトップページを指すという認識でおk

renderというのは、HTML文書を生成するメソッド。
ここではERBというライブラリを用いて生成する。
ERBで解釈可能なテキストをERBテンプレートと呼ぶ。
ERBテンプレートのファイルには拡張子erbをつける。

結果としてHTML文書が生成されるのなら、index.html.erbのように二重の拡張子をつけるのが一般的


原則ERBテンプレートはapp/viewsディレクトリにコントローラごとに分けて置く。
ファイル名にはアクション名を用いる。

つまり、staff/topコントローラのindexアクションで使用されるERBテンプレートの標準パスはapp/views/staff/top/index.html.erbとなる。

先ほどのrender action: "index"という文の意味は、標準パスにあるindexアクション用のERBテンプレートを用いてHTML文書を作成せよということになる。

ちなみに、アクションの中で一度もクライアント(ブラウザ)にレスポンスを返すメソッドが呼ばれなかった場合、暗黙裏にそのアクションに対応するERBテンプレートを用いてHTML文書が生成される。

つまりrender action:"index"は次のように省略することもできる!

def index
end

へー!!!知らんかった!

今回は明示的に呼び出してみる。

ちなみにブラウザにレスポンスを返すメソッドは次のようなものがある。
render
redirect_to
send_file
respond_with
他にもあるかもしれん

5.1.3 ERBテンプレートの作成

下記ディレクトリに、新規ファイルindex.html.erbを作成する。

app/views/staff/top
app/views/admin/top
app/views/customer/top

それぞれ下記のようにする

app/views/staff/top/index.html.erb
----------------------------------------
<% @title = "職員トップページ" %>
<h1><%= @title %></h1>
----------------------------------------
app/views/admin/top/index.html.erb
----------------------------------------
<% @title = "管理者トップページ" %>
<h1><%= @title %></h1>
----------------------------------------
app/views/customer/top/index.html.erb
----------------------------------------
<% @title = "顧客トップページ" %>
<h1><%= @title %></h1>
----------------------------------------

<% %>はrubyとして解釈 つまりruby起動して実行してハイ終了なモード
<%= %>はERBテンプレートに埋め込み つまりruby起動して実行してデータをhtmlに流し込んでから終了するなモード

bin/rails s -b 0.0.0.0

でサーバーを起動して

http://example.com:3000
http://baukis2.example.com:3000
http://localhost:3000

・・・ではなく、下記で画面を確認
http://localhost:3000
http://localhost:3000/staff
http://localhost:3000/admin
http://localhost:3000/customer
http://baukis2.example.com:3000
http://baukis2.example.com:3000/staff
http://baukis2.example.com:3000/admin
http://baukis2.example.com:3000/customer
http://baukis2.example.com:3000
http://baukis2.example.com:3000/staff
http://baukis2.example.com:3000/admin
http://baukis2.example.com:3000/customer

なるほど、railsトップページはそれぞれ全てそのままに、その下のURLがそれぞれ変更になったことを確認。

ここでよくわからんコラム
ERBテンプレートにおける文字列のエスケープ処理
ERBテンプレートに文字列を埋め込む際、それに含まれるHTML特殊文字(<>&")はエスケープ処理される。
つまり、次のような変換が行われる。

< &lt;
> &gt;
& &amp;
" &quot;

利用者が入力したHTML特殊文字を含む文字列をページに表示しても、ページが乱れたり、不正なJavaScriptコードが実行されたりしないようにするための予防措置。
しかし、HTML特殊文字を含む文字列をそのままERBテンプレートに挿入したいこともある。
そのため、Railsにはちょっとした仕掛けが用意されている。
主役を演じるのはActiveSupport::SafeBufferというクラス。
Stringクラスを継承。
このクラスのインスタンスはERBテンプレートに埋め込まれる際にエスケープ処理されないという性質を持つ。
つまりエスケープ処理をしないで文字列をERBテンプレートに埋め込むには文字列をActiveSupport::SafeBufferオブジェクトに変換すればいい。

@fragment = "<p>Hello World!</p>"
@fragment.html_safe
raw(@fragment)

つまり・・・?

<% @fragment = "<p>Hello World!</p>" %>
<%= @fragment %>
<%= @fragment.html_safe %>
<%= raw(@fragment) %>

で結果を見ればいいな?

あ、なるほどね!
2行目だと、記号が表示されちゃう!
3,4行目だと、その記号自体の意味も反映してくれるのか!
これは覚えなきゃ!

5.1.4 レイアウト

めっちゃ短いコードしか書いてないにも関わらず、ブラウザのコードを確認してみるとめっちゃコード多い。

なぜか?

それはapp/views/layouts/application.html.erbファイルのしわざ

このファイルの<%= yield %>に、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>
----------------------------------------

stylesheet_link_tagは、適用するcssタグを指定
applicationを指定すると、app/assets/stylesheets/application.cssが読み込まれる
mediaはprintを指定すると印刷物が対象となり、screenを指定すれば画面が対象になる。
すべての対象とするならばall

javascript_pack_tagは、適用するjavascriptを指定
applicationを指定すると、app/javascript/packs/application.jsが読み込まれる

"data-turbolinks-track":trueは画面遷移を高速化させるライブラリを有効にするために必要らしい

5.1.5 部分テンプレート

もはやテンプレートばりの作業だが、headerとfooterを追加する。

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>
   <div id="wrapper">
     <%= render "shared/header" %>
     <div id="container">
       <%= yield %>
     </div>
     <%= render "shared/footer" %>
   </div>
 </body>
</html>
----------------------------------------

headerとfooterがないのでこの時点ではエラーを吐かれる。

なので、下記を新規作成。
app/views/shared/_header.html.erb
app/views/shared/_footer.html.erb


app/views/shared/_header.html.erb
----------------------------------------
<header>
 <span class="logo-mark">BAUKIS2</span>
</header>
----------------------------------------
app/views/shared/_footer.html.erb
----------------------------------------
<footer>
 <p>&copy; 2019 Tsutomu Kuroda</p>
</footer>
----------------------------------------

これで、ヘッダーとフッターができた。

_で始まるファイル名は部分テンプレートと呼ぶ。
HTML文書を構成する部品と考える。

rbのrenderメソッドと、erbのrenderメソッドはやや働きが異なる。
前者はアクション名を、後者は部分テンプレート名を使う。

5.1.6 ヘルパーメソッドの定義

ERBテンプレート(レイアウトや部分テンプレートを含む)の中で使用できるメソッドをヘルパーメソッドと呼ぶ。部分テンプレートを読み込むrenderはヘルパーメソッドの一種。

ヘルパーメソッドは自分で定義できる。
app/helpersディレクトリにある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修正後
----------------------------------------
<!DOCTYPE html>
<html>
 <head>
   <%# app/helpers/application_helper.rbでdocument_titleは定義 %>
   <title><%= document_title %></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>
   <div id="wrapper">
     <%= render "shared/header" %>
     <div id="container">
       <%= yield %>
     </div>
     <%= render "shared/footer" %>
   </div>
 </body>
</html>
----------------------------------------

これでブラウザのタイトルバーのテキストがページごとに変わるようになった!イイネ!

5.2 Sass/SCSS

Sass/SCSSを用いて利用者別のトップページにスタイルを適用する方法を学ぶ

5.2.1 アセットパイプライン

初期状態のrailsアプリケーションでは、app/assetsディレクトリにimages,javascript,stylesheetsという3つのサブディレクトリが存在する。
画像ファイル、JavaScriptファイル、CSSファイルを置くためのディレクトリ。
railsではこれらのファイルをアセット(assets)と呼ぶ。

アセットパイプライン最大の売りは、ファイルの変換と結合。

たとえば、app/assets/stylesheetsディレクトリにapplication.css,layout.scss,errors.scssという3つのファイルがあるとする。
アセットパイプラインは、これら3つのファイルから1個のCSSファイルを生成する。その際にSCSS形式をCSS形式に変換し、複数のファイルを1つに結合する。

ファイルを結合する最大のメリットは、ブラウザとrailsアプリケーション間のHTTP通信の回数が減ること。
HTTP通信は接続開始処理のところで比較的大きな負荷をサーバーに掛けるため、回数をへらすことが大事。

5.2.2 Sass/SCSSとは

Sass(Syntacically Awesome Stylesheets)は、CSS(Cascading Style Sheets)を拡張したスタイルシート言語。
CSS3と互換性を保ちつつ、ネスティング、変数、ミックスインなどの特徴を備えている。
ブラウザはSassを理解できないため、サーバー側でSassをCSSに変換してブラウザに送る必要がある。
この処理をコンパイルと呼ぶ。

Sassにはインデント(字下げ)によって構造を表現するオリジナルの書式と、波括弧({})によって構造を表現するSCSSと呼ばれる書式がある。

本書ではSCSSを採用する。SCSSで記述されたスタイルシートのファイルには.scssという拡張子を付ける。
かつては.css.scssという二重の拡張子をつける流儀もあったが、現在はこの拡張子を使用すると警告が表示される。

railsアプリケーションにおけるSCSSの置き場所は、app/assets/stylesheetsディレクトリ

5.2.3 スタイルシートの切り替え

application.css

app/assets/stylesheetsディレクトリにはapplications.cssというファイルが1つだけ存在しており、次のような内容が書かれている。

app/assets/stylesheets/application.css
----------------------------------------
/*
* This is a manifest file that'll be compiled into application.css, which will include all the files
* listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
* vendor/assets/stylesheets directory can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
* files in this directory. Styles in this file should be added after the last require_* statement.
* It is generally better to create a new file per style scope.
*
*= require_tree .
*= require_self
*/
----------------------------------------


コメント行は本来無視されるが、railsの場合コメント行にも実は意味がある。なんてこった!

*=で始まる行はディレクティブと呼ばれる。
ここでアセットパイプラインの設定を行う。

require_treeディレクティブでは、アセットパイプラインが処理をするファイルの範囲を設定する。
*=require_treeは、
app/assets/stylesheetsディレクトリ以下の全ファイルを処理対象とする。
Baukis2ではここをrequire_tree ./staffのように書き換えることによって処理対象のディレクトリを限定することになる。

*=require_selfディレクティブは、自分自身を表す。
application.cssのことを表す。
本書ではあとで削除する。

スタイルシートの分離

Baukis2は利用者別に大きく3つの部分に分かれており、それぞれの役割がかなり異なるため、開発が進むにつれてスタイルの差異が拡大していくものと予想される。
そのためスタイルシートを完全に分離する。

app/assets/stylesheetsディレクトリのapplication.cssを削除する。

新規ファイルstaff.cssを作成する。

app/assets/stylesheets/staff.css
----------------------------------------
/*
*= require_tree ./staff
*/
----------------------------------------

そして、config/initializersディレクトリにあるファイルassets.rbをテキストエディタで開き、
コメント行を削除し、シングルクォートをダブルに置き換える。

config/initializers/assets.rb修正後
----------------------------------------
Rails.application.config.assets.version = "1.0"
Rails.application.config.assets.paths << Rails.root.join("node_modules")
----------------------------------------

それを次のように書き換える。

config/initializers/assets.rb修正後
----------------------------------------
Rails.application.config.assets.version = "1.0"
Rails.application.config.assets.paths << Rails.root.join("node_modules")
Rails.application.config.assets.precompile += %w(staff.css)
----------------------------------------

この修正により、staff.cssがアセットプリコンパイルの対象に加わる。

次に、app/assets/stylesheetsディレクトリにstaffディレクトリを作成し、
その下にlayout.scssという新規ファイルを次のような形で作成する。


app/assets/stylesheets/staff/layout.scss
----------------------------------------
html,body{
margin: 0;
padding: 0;
height: 100%;
}
div#wrapper{
 position: relative;
 box-sizing: border-box;
 min-height: 100%;
 margin: 0 auto;
 padding-bottom: 48px;
 background-color: #cccccc;
}
----------------------------------------


続いて、app/views/layoutsディレクトリのapplication.html.erbのファイル名をstaff.html.erbに変更し、その内容を次のように書き換える。

app/views/layouts/staff.html.erb修正後
----------------------------------------
<!DOCTYPE html>
<html>
 <head>
   <%# document_titleはapp/helpers/application_helper.rbで定義 %>
   <title><%= document_title %></title>
   <%= csrf_meta_tags %>
   <%= csp_meta_tag %>
   <%= stylesheet_link_tag 'staff', media: 'all', 'data-turbolinks-track': 'reload' %>
   <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
 </head>
 <body>
   <div id="wrapper">
     <%= render "shared/header" %>
     <div id="container">
       <%= yield %>
     </div>
     <%= render "shared/footer" %>
   </div>
 </body>
</html>
----------------------------------------

えっ、application.erbからstaff.html.erbに変更しても問題ないの?
cssはstaff用に変わったね
javascriptはapplicationからstaff用に変えてないね

最後に、中身が空っぽのapp/controllers/application_controller.rbを次のように変更する。

app/controllers/application_controller.rb修正後
----------------------------------------
class ApplicationController < ActionController::Base
 layout :set_layout
 
 private def set_layout
   if params[:controller].match(%r{\A(staff|admin|customer)/})
     Regexp.last_match[1]
   else
     "customer"
   end
 end
end
----------------------------------------

macでバックスラッシュを打つ時はoption + ¥ で出る!

変更の目的は、レイアウトを決定する仕組みのカスタマイズ。
通常はコントローラ名と同じ名前のレイアウトが優先的に選択され、それが存在しなければapplicationという名前のレイアウトが選択される。

[staff/topコントローラの場合]
第一候補:app/views/layouts/staff/top.html.erb
第二候補:app/views/layouts/application.html.erb

ただ、そんなものはない。

じゃあどうやって決定するか?
そこでapp/controllers/application_controller.rbの出番。
layout :set_layoutは、レイアウトを決定するメソッドを指定する。
set_layoutメソッドがすぐ下にあるけど、それで決めるよって言ってる。
params[:controller]は、現在選択されているコントローラの名前を取得できる。
つまり今回の場合"staff/top"。

他のは正規表現うんぬんでなんか難しいからいいや。

http://example.com:3000/staffを開いてみるとcssが適用されているのが確認できる。

ここでコラム
ApplicationControllerとは何か
すべてのコントローラの親クラスで、自らが所有するメソッドを子や孫に引き渡すことにより、その役割は終わる。

5.2.4 ヘッダとフッタのスタイル

スタイル適用作業を更に進める。
ヘッダとフッタに適用する。

職員サイト用のlayout.scssを次のように修正する。

app/assets/stylesheets/staff/layout.scss修正後
----------------------------------------
html,body{
margin: 0;
padding: 0;
height: 100%;
}
div#wrapper{
 position: relative;
 box-sizing: border-box;
 min-height: 100%;
 margin: 0 auto;
 padding-bottom: 48px;
 background-color: #cccccc;
}
header{
 padding: 5px;
 background-color: #448888;
 color: #eeeeee;
 span.logo-mark{
     font-weight: bold;
 }
}
footer{
 bottom: 0;
 position: absolute;
 width: 100%;
 background-color: #666666;
 color: #eeeeee;
 p{
     text-align: center;
     padding: 5px;
     margin: 0;
 }
}
----------------------------------------

ここで再開。
学習を再開するためにやること
cd /Users/el93019205/rails6-compose
docker-compose up -d
docker-compose exec web bash

cd baukis2
bin/rails s -b 0.0.0.0

以下は終わるためのコマンド
exit
cd /Users/el93019205/rails6-compose
docker-compose stop
cd

5.2.5 見出し(h1要素)のスタイル

app/asset/stylesheets/staffディレクトリに新規ファイルcontainer.scssを次の内容で作成する。

app/asset/stylesheets/staff/container.scss新規作成
----------------------------------------
div#wrapper{
 div#container{
 	h1{
 		margin: 0;
 		padding: 9px 6px;
 		font-size: 16px;
 		font-weight: normal;
 		background-color: #1a3333;
 		color: #eeeeee
 	}
 }
}
----------------------------------------

stylesheetsのstaff.cssで、アセットパイプラインとしてstaffディレクトリの中にあるものを全部つなげてくれるから、
container.scssをわざわざ読み込みするみたいなものはどこにも書かなくていいようになってるのか!
なるほどね!
これでファイル分けが簡単にできるようになってるのね!

5.2.6 色を変数で表現する

管理が大変になっていくから、色に名前をつけていく

app/assets/stylesheets/staff/_colors.scss新規作成
----------------------------------------
/* グレー系 */
$dark_gray: #666666;
$gray: #cccccc;
$light_gray: #eeeeee;
$very_light_gray: #fafafa;
/* シアン系 */
$dark_cyan: #448888;
$very_dark_cyan: darken($dark_cyan, 25%);
----------------------------------------

Sass/SCSSには数多くの色関数が用意されている。
https://sass-lang.com/

これをインポートするのは、下記のようにする
@import "colors";

layout.scssを修正していく

app/assets/stylesheets/staff/layout.scss修正後
----------------------------------------
@import "colors";
html,body{
margin: 0;
padding: 0;
height: 100%;
}
div#wrapper{
 position: relative;
 box-sizing: border-box;
 min-height: 100%;
 margin: 0 auto;
 padding-bottom: 48px;
 background-color: $gray;
}
header{
 padding: 5px;
 background-color: $dark_cyan;
 color: $very_light_gray;
 span.logo-mark{
     font-weight: bold;
 }
}
footer{
 bottom: 0;
 position: absolute;
 width: 100%;
 background-color: $dark_gray;
 color: $very_light_gray;
 p{
     text-align: center;
     padding: 5px;
     margin: 0;
 }
}
----------------------------------------

ファイル名の先頭がアンダーバーである理由は?
→アンダースコアで始まる名前を持つSCSSはSCSSパーシャルと呼ぶ。
@importディレクティブによって他のSCSSファイルで読み込むことができる。

筆者の経験上は、色名を変数名として定義するのがいい。

同様に、container.scssについても色の値を変数で置き換えていく。

app/assets/stylesheets/staff/container.scss修正後
----------------------------------------
@import "colors";
div#wrapper{
 div#container{
 	h1{
 		margin: 0;
 		padding: 9px 6px;
 		font-size: 16px;
 		font-weight: normal;
 		background-color: $very_dark_cyan;
 		color: $light_gray;
 	}
 }
}
----------------------------------------

ちなみに誤字があるとエラーになる。
恐れずに安心して修正していっていい。


5.2.7 寸法を変数で表現する

色と同様、マージンやパディングの幅、フォントサイズなどの寸法に関しても、名前をつけて管理することにする。
こういうのいいな!

app/assets/stylesheets/staff/_dimensions.scss新規作成
----------------------------------------
/* マージン、パディング */
$narrow: 2px;
$moderate:6px;
$wide: 10px;
$very_wide: 20px;
/* フォントサイズ */
$tiny: 8px;
$small: 10px;
$normal: 12px;
$large: 16px;
$huge: 20px;
/* 行の高さ */
$standard_line_height: 16px;
----------------------------------------

そしてlayout.cssを書き換えていく。

app/assets/stylesheets/staff/layout.css修正
----------------------------------------
@import "colors";
@import "dimensions";
html,body{
margin: 0;
padding: 0;
height: 100%;
}
div#wrapper{
 position: relative;
 box-sizing: border-box;
 min-height: 100%;
 margin: 0 auto;
 padding-bottom: ( $wide + $moderate) * 2 + $standard_line_height;
 background-color: $gray;
}
header{
 padding: $moderate;
 background-color: $dark_cyan;
 color: $very_light_gray;
 span.logo-mark{
     font-weight: bold;
 }
}
footer{
 bottom: 0;
 position: absolute;
 width: 100%;
 background-color: $dark_gray;
 color: $very_light_gray;
 p{
     text-align: center;
     padding: $moderate;
     margin: 0;
 }
}
----------------------------------------

ブラウザをリロードして、ビジュアルデザインが崩れないことを確かめる。

あんまりくずれてない!


5.3 アセットのプリコンパイル

5.3.1 productionモード

railsアプリケーションには3つの動作モードがある。
development(開発)
test(テスト)
production(本番)

動作モードと言われるのは、一般的には環境(environment)と呼んでいる。
本書では紛らわしいからモードか動作モードで統一

本番モードはjsやcssをブラウザに返さない。
なぜなら、apacheやnginxなどのwebサーバーがこれらのファイルを取り扱うから。

5.3.2 productionモード用のデータベースの作成

productionモード用のデータベースを作成するために、config/database,ymlを修正する。

config/database,yml修正後
----------------------------------------
:
production:
 <<: *default
 database: baukis2_production
 username: postgres
 password: <%= ENV['BAUKIS2_DATABASE_PASSWORD'] %>
----------------------------------------

もともとはbaukis2となっていたusernameを。postgresに変更した。
そして、webコンテナのターミナルで次のコマンドを実行する。
bin/rails db:create RAILS_ENV=production

----------------------------------------
bash-4.4$ bin/rails db:create RAILS_ENV=production
Created database 'baukis2_production'
bash-4.4$ 
----------------------------------------


5.3.3 assets:precompileタスクの実行

続いて、アセットプリコンパイルを実行する
bin/rails assets:precompile

----------------------------------------
bash-4.4$ bin/rails assets:precompile
yarn install v1.12.3
[1/4] Resolving packages...
success Already up-to-date.
Done in 1.00s.
yarn install v1.12.3
[1/4] Resolving packages...
success Already up-to-date.
Done in 0.98s.
I, [2020-02-22T14:44:03.990433 #100]  INFO -- : Writing /apps/baukis2/public/assets/staff-e32e08e83ca2b51a9988a0c31aed5cbae32d7829f671388e1b8e9b749dc6b8f9.css
I, [2020-02-22T14:44:03.990936 #100]  INFO -- : Writing /apps/baukis2/public/assets/staff-e32e08e83ca2b51a9988a0c31aed5cbae32d7829f671388e1b8e9b749dc6b8f9.css.gz
I, [2020-02-22T14:44:03.991363 #100]  INFO -- : Writing /apps/baukis2/public/assets/manifest-cadda289ef9c70eaa0879a36e6263cb33f7523a16b3ef862e0b8609cdc2bdab1.js
I, [2020-02-22T14:44:03.991694 #100]  INFO -- : Writing /apps/baukis2/public/assets/manifest-cadda289ef9c70eaa0879a36e6263cb33f7523a16b3ef862e0b8609cdc2bdab1.js.gz
I, [2020-02-22T14:44:03.992336 #100]  INFO -- : Writing /apps/baukis2/public/assets/staff-e32e08e83ca2b51a9988a0c31aed5cbae32d7829f671388e1b8e9b749dc6b8f9.css
I, [2020-02-22T14:44:03.994117 #100]  INFO -- : Writing /apps/baukis2/public/assets/staff-e32e08e83ca2b51a9988a0c31aed5cbae32d7829f671388e1b8e9b749dc6b8f9.css.gz
Everything's up-to-date. Nothing to do
bash-4.4$ 
----------------------------------------

public/assetsディレクトリに1個のJavaScript、1個のCSS、2個のgzファイルが生成される。
gzファイルはJavaScriptファイルとCSSファイルをGZipで圧縮したもの。
これってcssのディレクトリ増やすたびに実行しなきゃいけないかなぁ・・・?

5.3.4 暗号化された資格情報

railsアプリケーションをproductionモードで稼働させるときに留意しなければならないのは、パスワード、秘密鍵、APIへのアクセストークンなどの資格情報(credentials)を、サーバー上でどのように保持するかということ。
これらの情報は、サーバー管理者以外の目から隠す必要がある。
railsには「暗号化された資格情報(Encrypted Credentials)」という仕組みが初めから組み込まれている。

資格情報はconfigディレクトリにある次の2つのファイルを用いて保持される。

config/credentials.yml.enc
config/master.key

前者は資格情報が暗号化されて記録されている。
後者は暗号を解くための鍵。

この2つのファイルを別々に保管すれば安全に資格情報を取り扱うことができる。

railsアプリケーションのソースコードをGithubなどのリポジトリで管理する場合、master.keyは管理対象から外す。

次の行は、credentials.yml.encとmaster.keyの組み合わせが正しいかどうかを確認するためのコマンド
EDITOR=vim bin/rails credentials:edit

:qと入力して、そのままテキストエディタを閉じる。

----------------------------------------
File encrypted and saved.
----------------------------------------

master.keyが存在しないときや、credentials.yml.encとmaster.keyの組み合わせが正しくないときは、次のようなエラーメッセージが表示される。

----------------------------------------
Couldn't decrypt config/credentials.yml.enc Perhaps you passed the wrong key?
----------------------------------------

その場合は、次のコマンドで2つのファイルを削除する
rm config/credentials.yml.enc config/master.key

そして、次のコマンドを実行してから、すぐにエディタを閉じる。

EDITOR=vim bin/rails credentials:edit

----------------------------------------
bash-4.4$ rm config/credentials.yml.enc config/master.key
bash-4.4$ EDITOR=vim bin/rails credentials:edit
Adding config/master.key to store the encryption key: 10dd567186f0a68b9006d31b09b5e9f4
Save this in a password manager your team can access.
If you lose the key, no one, including you, can access anything encrypted with it.
     create  config/master.key
File encrypted and saved.
bash-4.4$ 
----------------------------------------

そうすると、削除されたキーが2つ新しく作られる。

また、master.keyの名称をmastera.keyに変更してから
EDITOR=vim bin/rails credentials:edit
を実行すると、
Couldn't decrypt config/credentials.yml.enc. Perhaps you passed the wrong key?
の文章が確認できる。これはmaster.keyとcredentials.yml.encが一致した組み合わせでないことが確認できる。

確認できたら、master.key,mastera.key,credentials.yml.encを消しておく。
rm config/credentials.yml.enc config/master.key config/mastera.key

そして、次のコマンドを実行してからすぐに閉じる。
EDITOR=vim bin/rails credentials:edit

でおk

5.3.5 productionモードでBaukis2を起動

productionモードでBaukis2を起動する。
準備として次のコマンドを実行する。

export RAILS_SERVE_STATIC_FILES=1

原則productionモードではCSS,JavaScript,画像などの静的ファイルをRailsアプリケーションは返さない。
環境変数RAILS_SERVE_FILESに何らかの値をセットすると返すようになる。
productionモードでBaukis2を起動する。

bin/rails s -e production -b 0.0.0.0

ブラウザをリロードして前と同じ画面が表示されれば成功!

フィンガープリントについて
拡張子前の長いファイル名はフィンガープリントと呼ばれる。
CSSファイルの中身をMD5という関数で計算した結果。
ファイルの中身が変化するとMD5関数の結果がほぼ確実に変化する。
これはキャッシュ制御のため。
ブラウザやプロキシはネットワークアクセスを減らすためにCSSファイルなどをキャッシュに保存するが、この機能がときに問題を引き起こす。アプリケーション側でCSSファイルが書き換わってもブラウザ側ではページのスタイルが変わらないことがある。しかし、フィンガープリントによりファイル名を変えてしまえばこの問題を回避できる。

つまり、意識しなくても即座にCSSが適用されてくれるのはrailsの機能のおかげであるということ。
すごいねrails

5.4 演習問題

問題1

職員トップページと同様に、管理者トップページと顧客トップページに対してもレイアウトとスタイルシートを作成してください。
ただし、管理者トップページにはマゼンタ系の色、顧客トップページには黄色系の色を使用してください。
また、色を表す変数名もcyanをmagentaおよびyellowで置き換えてください。

5.2.3章から、customer,adminに関する記述がなくなった。なので、5.2.3章からcustomer,adminについても同じ操作をしていく。

新規ファイルcustomer.css,admin.cssを作成する。

app/assets/stylesheets/customer.css
----------------------------------------
/*
*= require_tree ./customer
*/
----------------------------------------
app/assets/stylesheets/admin.css
----------------------------------------
/*
*= require_tree ./admin
*/
----------------------------------------

そして、app/assets/stylesheets内に、staffフォルダをコピペし、それぞれをcustomer,adminとする。

そして、app/views/layoutsディレクトリのstaff.html.erbをコピペし、それぞれをcustomer,adminとする。
中身も、stylesheet_link_tagをそれぞれcustomer,adminに変更する。

app/views/layouts/customer.html.erb修正後
----------------------------------------
<!DOCTYPE html>
<html>
 <head>
   <%# document_titleはapp/helpers/application_helper.rbで定義 %>
   <title><%= document_title %></title>
   <%= csrf_meta_tags %>
   <%= csp_meta_tag %>
   <%= stylesheet_link_tag 'customer', media: 'all', 'data-turbolinks-track': 'reload' %>
   <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
 </head>
 <body>
   <div id="wrapper">
     <%= render "shared/header" %>
     <div id="container">
       <%= yield %>
     </div>
     <%= render "shared/footer" %>
   </div>
 </body>
</html>
----------------------------------------
app/views/layouts/admin.html.erb修正後
----------------------------------------
<!DOCTYPE html>
<html>
 <head>
   <%# document_titleはapp/helpers/application_helper.rbで定義 %>
   <title><%= document_title %></title>
   <%= csrf_meta_tags %>
   <%= csp_meta_tag %>
   <%= stylesheet_link_tag 'admin', media: 'all', 'data-turbolinks-track': 'reload' %>
   <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
 </head>
 <body>
   <div id="wrapper">
     <%= render "shared/header" %>
     <div id="container">
       <%= yield %>
     </div>
     <%= render "shared/footer" %>
   </div>
 </body>
</html>
----------------------------------------

「管理者トップページにはマゼンタ系の色、顧客トップページには黄色系の色を使用してください。」
を満たすために、それぞれ下記を修正する。


app/assets/stylesheets/admin/_colors.scss修正後
----------------------------------------
/* グレー系 */
$dark_gray: #666666;
$gray: #cccccc;
$light_gray: #eeeeee;
$very_light_gray: #fafafa;
/* マゼンタ系 */
$dark_magenta: #E85298;
$very_dark_magenta: darken($dark_magenta, 25%);
----------------------------------------
app/assets/stylesheets/customer/_colors.scss修正後
----------------------------------------
/* グレー系 */
$dark_gray: #666666;
$gray: #cccccc;
$light_gray: #eeeeee;
$very_light_gray: #fafafa;
/* イエロー系 */
$dark_yellow: #FFF33F;
$very_dark_yellow: darken($dark_yellow, 25%);
----------------------------------------

「管理者トップページにはマゼンタ系の色、顧客トップページには黄色系の色を使用してください。」
「色を表す変数名もcyanをmagentaおよびyellowで置き換えてください。」
を満たすために、それぞれ下記を修正する。

app/assets/stylesheets/admin/container.scss修正後
----------------------------------------
@import "colors";
div#wrapper{
 div#container{
 	h1{
 		margin: 0;
 		padding: 9px 6px;
 		font-size: 16px;
 		font-weight: normal;
 		background-color: $very_dark_magenta;
 		color: $light_gray;
 	}
 }
}
----------------------------------------
app/assets/stylesheets/admin/layout.scss修正後
----------------------------------------
@import "colors";
@import "dimensions";
html,body{
margin: 0;
padding: 0;
height: 100%;
}
div#wrapper{
 position: relative;
 box-sizing: border-box;
 min-height: 100%;
 margin: 0 auto;
 padding-bottom: ( $wide + $moderate) * 2 + $standard_line_height;
 background-color: $gray;
}
header{
 padding: $moderate;
 background-color: $dark_magenta;
 color: $very_light_gray;
 span.logo-mark{
     font-weight: bold;
 }
}
footer{
 bottom: 0;
 position: absolute;
 width: 100%;
 background-color: $dark_gray;
 color: $very_light_gray;
 p{
     text-align: center;
     padding: $moderate;
     margin: 0;
 }
}
----------------------------------------
app/assets/stylesheets/customer/container.scss修正後
----------------------------------------
@import "colors";
div#wrapper{
 div#container{
 	h1{
 		margin: 0;
 		padding: 9px 6px;
 		font-size: 16px;
 		font-weight: normal;
 		background-color: $very_dark_yellow;
 		color: $light_gray;
 	}
 }
}
----------------------------------------
app/assets/stylesheets/customer/layout.scss修正後
----------------------------------------
@import "colors";
@import "dimensions";
html,body{
margin: 0;
padding: 0;
height: 100%;
}
div#wrapper{
 position: relative;
 box-sizing: border-box;
 min-height: 100%;
 margin: 0 auto;
 padding-bottom: ( $wide + $moderate) * 2 + $standard_line_height;
 background-color: $gray;
}
header{
 padding: $moderate;
 background-color: $dark_yellow;
 color: $very_light_gray;
 span.logo-mark{
     font-weight: bold;
 }
}
footer{
 bottom: 0;
 position: absolute;
 width: 100%;
 background-color: $dark_gray;
 color: $very_light_gray;
 p{
     text-align: center;
     padding: $moderate;
     margin: 0;
 }
}
----------------------------------------


問題2

管理者用のCSSファイルと顧客用のCSSファイルがプリコンパイルの対象となるようにconfig/initializers/assets.rbを書き換えてください。

5.2.3章でやった修正を行う。

config/initializers/assets.rb修正後
----------------------------------------
Rails.application.config.assets.version = "1.0"
Rails.application.config.assets.paths << Rails.root.join("node_modules")
Rails.application.config.assets.precompile += %w(staff.css)
Rails.application.config.assets.precompile += %w(customer.css)
Rails.application.config.assets.precompile += %w(admin.css)
----------------------------------------


問題3

アセットのプリコンパイルを行って、productionモードでも管理者トップページと顧客トップページが正しく表示されることを確認してください。

bin/rails assets:precompile

----------------------------------------
bash-4.4$ bin/rails assets:precompile
yarn install v1.12.3
[1/4] Resolving packages...
success Already up-to-date.
Done in 0.91s.
yarn install v1.12.3
[1/4] Resolving packages...
success Already up-to-date.
Done in 0.93s.
I, [2020-02-22T16:08:29.967996 #310]  INFO -- : Writing /apps/baukis2/public/assets/admin-dd780e75948bce501dcf8ee95d114bdaf7bd2060ea77747e32274f88787a8b29.css
I, [2020-02-22T16:08:29.969054 #310]  INFO -- : Writing /apps/baukis2/public/assets/admin-dd780e75948bce501dcf8ee95d114bdaf7bd2060ea77747e32274f88787a8b29.css.gz
I, [2020-02-22T16:08:29.971791 #310]  INFO -- : Writing /apps/baukis2/public/assets/customer-7eaef309bcd60ca9c66aae983f3cb1d3ae063e10aa33082ab2913482442656b6.css
I, [2020-02-22T16:08:29.973402 #310]  INFO -- : Writing /apps/baukis2/public/assets/customer-7eaef309bcd60ca9c66aae983f3cb1d3ae063e10aa33082ab2913482442656b6.css.gz
I, [2020-02-22T16:08:29.981428 #310]  INFO -- : Writing /apps/baukis2/public/assets/admin-dd780e75948bce501dcf8ee95d114bdaf7bd2060ea77747e32274f88787a8b29.css.gz
I, [2020-02-22T16:08:29.982630 #310]  INFO -- : Writing /apps/baukis2/public/assets/customer-7eaef309bcd60ca9c66aae983f3cb1d3ae063e10aa33082ab2913482442656b6.css.gz
Everything's up-to-date. Nothing to do
bash-4.4$ 
----------------------------------------

EDITOR=vim bin/rails credentials:edit
:q

でFile encrypted and saved.となり、キーの対応が合っていることを確認する。

control+cでテスト用のサーバーをoffし、
bin/rails s -e production -b 0.0.0.0
で本番用サーバーを起動し、下記URLで問題なく表示されることを確認。
http://example.com:3000/staff
http://example.com:3000/customer
http://example.com:3000/admin

できた!!!

演習問題で指示されたとおりにBaukis2を修正したという前提で次章に進むため、必ず演習問題を解いてから次に進む必要あり。


この記事が気に入ったらサポートをしてみませんか?