コーディング未経験のPO/PdMのためのRails on Dockerハンズオン vol.4 - Static pages -

# はじめに
第４回目は、Static pages（静的なページ）を作ることにチャレンジしてみましょう！
そもそも静的なページとは、アクセスするユーザーや時間帯に関係なく同じコンテンツが表示されるページのことです。対義語は動的なページは例えばマイページのようなユーザーごとにコンテンツが変わってくるようなページのことですね。
静的なページのみで構築されているサイトを『Webサイト』、動的なページも存在するサイトを『Webアプリケーション』と呼び分けたりします。

今回は、静的なトップページを作っていきますよ！

# 前回のソースコード
前回のソースコードはこちらに格納してます。今回のだけやりたい場合はこちらからダウンロードしてください。

- [at946/rails_on_docker_handson at vol.03](https://github.com/at946/rails_on_docker_handson/tree/vol.03)

# Railsの初期設定
とその前に。
今回は日本で使われ日本で運用するアプリを想定するのですが、Railsはデフォルトでは英語が使われていたりUTC（協定世界時）が使われていたりと、そのまま日本でサービス展開しようとすると面倒な部分があります。
最初にこの設定をローカライズ（日本化）しておきましょう！

## Timezoneの設定
`Dockerfile`や`docker-compose.yml`でコンテナのタイムゾーンは日本に設定していましたね（`TZ=Asia/Tokyo`）。Railsアプリも同じように設定してあげます。

```diff:config/application.rb
  ...
  module App
    class Application < Rails::Application
      config.load_defaults 6.0
      config.generators.system_tests = nil
+
+     # Timezone
+     config.time_zone = 'Tokyo'
+     config.active_record.default_timezone = :local
    end
  end
```
`+`の行が追加の行です。
`time_zone`はRailsアプリが時間を扱うときにどのtimezoneで動くかを指定する設定でデフォルトだとUTCになってます。例えば`Time.current`で現在の時間を表示できたりするのですが、この結果をどのtimezoneで表示するかがこの設定で決まります。この後、Modelを保存したりするときなどもその作成日時などがこのtimezoneで設定されます。

`active_record.default_timezone`はDBに書き込まれている時間をどのtimezoneとして扱うかの設定です。

## 言語の設定
Railsではエラーメッセージなどが準備されているのですが、デフォルトでは英語で定義されています。日本でサービス展開する場合「？」となってしまうので、日本語化します。

```diff:config/application.rb
module App
  class Application < Rails::Application
    config.load_defaults 6.0
    config.generators.system_tests = nil

    # Timezone
    config.time_zone = 'Tokyo'
    config.active_record.default_timezone = :local
+
+   # Language
+   config.i18n.default_locale = :ja
  end
end
```
この設定で、`config/locales/`にあるyamlファイルの中から`ja:`で定義されている文字列が表示されるようになるんです。日本語版のファイルを作ってくださっている方がいらっしゃいますのでベースとして利用させていただきましょう。

[rails-i18n/ja.yml at master · svenfuchs/rails-i18n](https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/ja.yml)

こちらのファイルを`config/locales/ja.yml`として保存することで日本語化完了です！

ちなみに『i18n』は『internationalization』のことで『国際化』と訳されます。アクセスする国によって時間や言語を変えたりすることです（今回は日本オンリーに対応ですが...笑い）。頭の『i』とお尻の『n』の間に18文字あるので『i18n』と表現します。技術系だとこういうの最近多いっすよね？

# Bootstrap
まだまだ静的なページの作成には入りませんよ！次は、Bootstrapを使えるようにしていきましょう。

[Bootstrap](https://getbootstrap.com/)はTwitter社が開発したCSSフレームワークです。
レスポンシブデザインに標準で対応されており、CSSだけでなくJavascript（jQuery）も含まれています。
多くの人に使われているためインターネット上に情報があふれていますので初心者にも安心です。一方で、多くの人に使われているため似通ったデザインになってしまうので少し慣れてくると敬遠されがちな印象です。

## Boostrapをyarnでインストール
Rails５まではgemでインストールするのが主流だったと思うのですが、Rails6ではWebpackerが必須になったこともありパッケージマネージャー経由でインストールするのが主流になっていくと思われますのでその方法で。

まだコンテナを立ち上げていなかったですね。それではコンテナを立ち上げてコンテナの中でコマンドを実行していきましょう！

```
$ docker-compose up -d
$ docker-compose exec web ash
```

```
# yarn add bootstrap jquery popper.js
```
これでBootstrap関連のライブラリをインストールできたのでRailsアプリで使えるように設定していきます。

まずapplication.jsでBootstrapを読み込みます。

```diff:app/javascript/packs/application.js
  require("@rails/ujs").start()
  require("turbolinks").start()
  require("@rails/activestorage").start()
  require("channels")
+ require("bootstrap")
```

次にBootstrapをSCSSで読み込むために`application.css`を`application.scss`にリネームします。

```
# mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scss
```
ファイルの中身はCSSの記法で書かれているものなので一度全て削除して以下のように書き換えましょう。

```scss:app/assets/stylesheets/application.scss
@import 'bootstrap/scss/bootstrap';
```

最後にBootstrapと依存関係にある`jQuery`と`popper.js`の設定を追加してあげます。

```diff:config/webpack/environment.js
  const { environment } = require('@rails/webpack')
+
+ const webpack = require('webpack')
+
+ environment.plugins.append('Provide', new webpack.ProvidePlugin({
+   $: 'jquery/src/jquery',
+   jQuery: 'jquery/src/jquery',
+   Popper: ['popper.js', 'default']
+ }))

module.exports = environment
```
たったこれだけでBootstrapの準備が整いました。Bootstrapで用意されているあらゆるスタイルシートやjavascriptが利用可能になっちゃいました。
Bootstrapがどんなことができるかは[Bootstrap公式のDocumentation](https://getbootstrap.com/docs/4.3/getting-started/introduction/)を見るのが一番いいと思っているのですが、これだけの表現が上の設定でできるようになってしまったのです。

# Topページを作成する
いよいよ静的なページを作っていきます。
静的なページではModelのような動的なものはいらないのでMVCのVCがあればOKですね。
VC（ルーティングも！）は`rails generate controller`コマンドで作成することができます。今回は`static_pages` controllerで`home` actionを作ってみましょう。

```
# rails generate controller static_pages home
```
`rails generate controller NAME [action action]`の形式でコマンドを実行できます。actionは複数指定可能です。
慣習的に`NAME`は複数形を用います。

このコマンドだけですでに`http://localhost:3000/static_pages/home`へのRouting, Controller#Action, Viewが出来上がっているのでアクセスできるようになっていますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254216/c69c66db-5f22-56a4-b3c6-79409e74faba.png)

このコマンドで作成・更新されたファイルの中身をちょっとみていきましょう！

## Routing
```rb:config/routes.rb
Rails.application.routes.draw do
  get 'static_pages/home'
end
```
`get 'static_pages/home'`の行が追加されてます。前回は`resouces`メソッドを使ったルーティングの指定の仕方でしたが、このように一つ一つのルートを定義することもできるのです。
これだけで「`static_pages/home`のパスに`get`メソッドできたリクエストを`static_pages` controllerの`home` actionにルーティングする」ことを定義しています。

## Controller
```rb:app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
  def home
  end
end
```
`home`アクションが定義されていますね。特段処理はないので、`app/views/static_pages/home.html.erb`をレンダリングするのみです。

## View
```erb:app/views/static_pages/home.html.erb
<h1>StaticPages#home</h1>
<p>Find me in app/views/static_pages/home.html.erb</p>
```
`app/views/static_pages/home.html.erb`ファイルが生成されています。
中身も先ほど`http://localhost:3000/static_pages/home`と同じものが表示されていることがわかりますね。

# ルートパスをTopページにする
現状ルートパス（`http://localhost:3000`）にアクセスするとHello worldのページが表示されています。本当はこのURLにアクセスしたときにTopページを表示させたいのでルーティングの設定を更新していきます。

```diff:config/routes.rb
Rails.application.routes.draw do
- get 'static_pages/home'
+ root 'static_pages#home'
end
```
ルートパスの設定の仕方は`root '[controller_name]#[action_name]'とするだけです！

試しに`http://localhost:3000/`にアクセスしてみてください。Topページが表示されるようになりましたね。
また`http://localhost:3000/static_pages/home`にもう一度アクセスしてみましょう。`get 'static_pages/home'`を削除してるので以下のようにそんなルートないよとエラーになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254216/ec409484-ecda-1feb-9b99-283e1452ccdd.png)

# Bootstrapでページを装飾する
にしても味気ないページですよね。ということでBootstrapのCSSを使いながらいい感じのページに装飾していきましょう！

CSSはHTMLのスタイル（色とか大きさとか）をまとめた変数みたいなものです。HTMLタグ（\<h1>とか\<p>とか）にclass属性をつけることでそのスタイルが適用されます。SCSSはCSSを書きやすくしたものです（なので本質はCSS）。

```html
<h1 class="hoge">Hello.</h1>
```

```scss
.hoge {
  font-size: 32px;
  color: red;
}
```
これで32pxの赤文字で"Hello."が表示されるようになるってイメージですね。

## Topページのコンテンツを装飾する
ではまず、`app/views/static_pages/home.html.erb`を更新していい感じのTopページを作っていきましょう。

```erb:app/views/static_pages/home.html.erb
<div class="jumbotron mb-0">
  <div class="container text-center">
    <h1>Welcome to Sample App.</h1>
    <h2>Twitterみたいなアプリです。</h2>
    <%= link_to "Sign up now!", "#", class: "btn btn-lg btn-primary mt-5" %>
  </div>
</div>
```
ここに出てくる`jumbotron`, `container`, `text-center`, `btn`, `btn-lg`, `btn-primary`, `mt-5`はすべてBootstrapのclassです。Bootstrapのclassの使い方はしっかりと[公式のDocumantation](https://getbootstrap.com/docs/4.4/getting-started/introduction/)があるのでそちらをみてみましょう。実際に自分で何かを作るとなるとこういう公式ドキュメントと向き合うことが一番の近道だったりするのでここでは説明しないっす。

１つだけ、ERBコードがありますね。

```erb:app/views/static_pages/home.html.erb
<%= link_to "Sing up now!", "#", class: "btn btn-lg btn-primary mt-5" %>
```
`link_to`はリンクを作るためのメソッドです。HTML的にいえば`<a>`タグを作ってくれるということです。
`link_to [表示文字], [リンク先], [options]`の構文になってまして、今回の例だと以下のような`<a>`タグが出来上がります。

```html
<a href="#" class="btn btn-lg btn-primary mt-5">Sign up now!</a>
```
リンク文字列やリンク先などに変数を指定でき（例えばルートパスはroot_pathが変数として割り当てられている）るのでERBファイルでリンクを作成する場合多用するコードなので覚えておきましょう。
リンク先として#を指定していますが、まだ遷移先のページを作成していないので仮置きしているだけです（#を指定しておくとリンクを押しても今いるページから遷移しないです。）

編集ができたらトップページをリロードしてみましょう。以下のページになっていれば成功です！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254216/e8d7262d-fc82-ffed-6517-df4b3bbe45b1.png)

ふへー。ぽくなってきましたね。

ただHeaderとかFooterとかも欲しくなってきました。

## ヘッダーを装飾する
突然ですが、ブラウザでトップページのソースコードをみてみましょう。（右クリックで「ページのソースを表示する」を選択するとみれます。）
`app/views/static_pages/home.html.erb`に全く書いた記憶がないもの、例えば`<head>`タグとかがありますよね。

```html:Topページ
<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="3702TRDf2wiVe1ErXV1NWoksR1sWw1+LO31miZuonos9K8zOmMwJ+VotF3ZXCPRP+g9IiKoZovoA8HpIjLjqmA==" />
    

    <link rel="stylesheet" media="all" href="/assets/application.debug-9519f0a34796e622c941135a612890361ca8a44f05d715927aaa1575ce29c235.css" data-turbolinks-track="reload" />
    <script src="/packs/js/application-923746675d9ea6d857bd.js" data-turbolinks-track="reload"></script>
  </head>

  <body>
    <div class="jumbotron">
      <div class="container text-center">
        <h1>Welcome to Sample App.</h1>
        <h2>Twitterみたいなアプリです。</h2>
        <a class="btn btn-lg btn-primary mt-5" href="#">Sign up now!</a>
      </div>
    </div>
  </body>
</html>
```
これはなんでしょう？:thinking: 

実はRailsアプリケーションではViewファイルの中でもLayoutと呼ばれるやつがいます。こいつはなにかというと、ページで共通な部分を表現してくれるものです。デフォルトで`app/views/layouts/application.html.erb`のレイアウトファイルが利用されています。ちょっと中を覗いてみましょう。

```erb:app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>App</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>
```
ERBコードが入っているので少し表現は違いますが、Topページのソースコードと似た構文をしていることがわかります。実は最終的に表示されているHTMLは`app/views/static_pages/home.html.erb`がこの`app/views/layouts/application.html.erb`の`<%= yield %>`に代入されたものです。

少しだけ`app/views/layouts/application.html.erb`の中身をご紹介。
まず全体の構文ですが、HTMLの基本の構文が記述されていますね。

```HTML
<!DOCTYPE html>
<html>
  <head>
    ...
  </head>

  <body>
    ...
  </body>
</html>
```

`<body>`の中の`yeild`については上で話した通りで、actionのviewファイルの中身が代入されるようになっています。

`<head>`の中はどうでしょうか？

### title
`title`はブラウザのタブのところに表示される文字列です。今だと`App`と指定されているのでそれが表示されていますね。

### scrf_meta_tags
CSRF（Cross-Site Request Forgery）対策のための記述です。今回のTopページではあまり活躍しませんが、POSTリクエストを飛ばすページで活躍します。簡単にいえば、正しいユーザーからのリクエストなのかというリクエストの真正性（Authenticity）を検証するために必要なことを開発者が意識せずともRailsがカバーしてくれるようになるとのこと。

これを有効にするためにはApplicationControllerで`protect_from_forgery`メソッドを有効にする必要があります。

```diff:app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
+ protect_from_forgery with: :exception
end
```

### csp_meta_tag
CSP（Content Security Policy）に必要なタグを生成してくれるコードです。CSPはXSS（Cross Site Scripting）を防ぐためのもので、コンテンツの提供元や取得方法を制限する手法です。別途、制限を設定することで動作するようになります。ここでは紹介程度。

### stylesheet_link_tag
stylesheetの読み込み。`app/assets/stylesheets/application.css[scss]`を読み込んでくれている。

### javascript_pack_tag
javascriptの読み込み。`app/javascript/packs/application.js`を読み込んでくれている。

ってな具合です。

さて、長々と話してしまいましたが、本当に言いたかったことは『ヘッダーやフッターは各ページ個別のものではなく、サイトで共通のものであるはずなので、レイアウトファイルに記述するんだよ』ということです。

では、ヘッダーを`app/views/layouts/application.html.erb`に記述します！

```diff:app/views/layouts/application.html.erb
  ...
  <body>
+   <header class="navbar navbar-dark navbar-expand bg-dark">
+     <div class="container">
+       <%= link_to "sample app", root_path, class: "navbar-brand" %>
+       <ul class="navbar-nav">
+         <li class="nav-item"><%= link_to "Home", root_path, class: "nav-link" %></li>
+         <li class="nav-item"><%= link_to "Sign in", "#", class: "nav-link" %></li>
+       </ul>
+     </div>
+   </header>
+
    <%= yield %>
  </body>
  ...
```
このあたりもBootstrapの公式ドキュメントを参考に記述してみました => [Navbar · Bootstrap](https://getbootstrap.com/docs/4.4/components/navbar/)

Topページにアクセスしてみましょう。以下のようになっていれば成功です！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254216/150f6de7-d33b-2c32-3357-3a00bcd19ef2.png)
おー、どんどんぽくなってきましたね！

## フッターを装飾する
最後にフッターも付けちゃいましょう！今回はコピーライトを書いているくらいのフッターをば。

フッターは`<footer>`タグを使います。

```diff:app/views/layouts/application.html.erb
  ...
  <body>
    <header class="navbar navbar-dark navbar-expand bg-dark">
      <div class="container">
        <%= link_to "sample app", root_path, class: "navbar-brand" %>
        <ul class="navbar-nav">
          <li class="nav-item"><%= link_to "Home", root_path, class: "nav-link" %></li>
          <li class="nav-item"><%= link_to "Sign in", "#", class: "nav-link" %></li>
        </ul>
      </div>
    </header>

    <%= yield %>
+
+   <footer class="bg-dark">
+     <p class="text-center text-white py-2 mb-0">(c) Hoge Inc. All Rights Reserved.</p>
+   </footer>
  </body>
  ...
```
特別難しいところはありませんね。再度Topページにアクセスします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254216/317aa432-c9d3-94ab-baa3-2831b3097293.png)
おー、ぽい。ぽいのですが、ブラウザの下の方に余白ができているのが気になりますね...
表示するコンテンツがブラウザの縦サイズに合わない場合は、フッターは画面の最下部に表示されるようにしたい...

ということで少しCSSをいじってみましょう。

```diff:app/assets/stylesheets/application.scss
  @import 'bootstrap/scss/bootstrap';
+
+ body {
+   display: flex;
+   flex-direction: column;
+   min-height: 100vh;
+ }
+
+ footer {
+   margin-top: auto;
+ }
```
本当はfooter用のファイルを作って`appliction.scss`で`@import`する方が整理されるのでいいのですが、今回は分量も少ないのでひとまず`application.scss`に記述します。

これで何をしているかというと、まず`body`タグに対して`display: flex;`をあててます。これはFlexboxという要素をきれいに横並びや縦並びでレイアウトしてくれるレイアウトモジュールです。
`flex-direction: column;`と定義しているので縦方向に要素を並べてくれます。
そして、`min-height: 100vh;`を定義しているので`body`タグで囲まれた要素は最低ブラウザいっぱいの高さを持つ要素に指定されたことになります。

今、`body`タグの中には`header`, `<%= yeild %>の中のdiv`, `footer`の3つの要素が同じレベルに存在しています。これを縦方向に並べていることになるんですね。
この時、Flexboxの親要素（今回だと`body`）をコンテナ、子要素（今回だと`header`, `div`, `footer`）をアイテムと呼びます。

`footer`には`margin-top: auto;`が定義されています。これは親要素に対して、この要素の上部に最大限のmargin（余白）を付与することを表していて、簡単に言うと親要素の一番下に配置するってことになります。
今、親要素の`body`は縦に最小で100vhの高さを持ちます。コンテンツが足りない場合は`body`は100vhの高さになるので`footer`は100vhの一番下に位置します。コンテンツが100vh以上の場合は`body`も`header`, `div`, `footer`の3要素の高さの合計が高さになるので、`footer`は自然な形で`div`のすぐ下に配置されることになります。

さてさて、ではTopページをリロードしてみてください！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254216/efa0313d-85e0-6b18-3cd3-101177490ece.png)
とてもいい感じになりましたね！

## スマートフォンに対応する
PCだといい感じに表示されるのですが、スマートフォンだと実はとても見にくい状態になっています。ChromeのDeveloper toolsなどで確かめてみてください（[Chrome DevTools での Device Mode によるモバイル端末のシミュレート](https://developers.google.com/web/tools/chrome-devtools/device-mode?hl=ja)）

BootstrapはもともとResponsive Design（ブラウザの横幅に合わせてCSSが変わる）に対応しているので、Viewport設定の1行を`head`タグ内に挿入するだけでいい感じのデザインになります。

```diff:app/views/layouts/application.html.erb
  ...
  <head>
    <title>App</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
+   <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>
  ...
```
呪文みたいな感じで書いちゃうことが多いのですが、意味は「[もう逃げない。HTMLのviewportをちゃんと理解する - Qiita](https://qiita.com/ryounagaoka/items/045b2808a5ed43f96607)」の記事が参考になりました。

スマホモードでリロードしてみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254216/635cda00-264d-cf21-c904-694f0742e479.png)
文字の大きさもいい感じになりましたね。

# Google Fontsでフォントを変える
んー。デザインはよくなってきたけどフォントがデフォルトっぽくて気になるなぁ...
フォントはこのアプリを使うユーザーの端末にフォントがインストールされていないと使えなかったりするのであんまり冒険できないところだったりします。アプリケーションの中でフォントを配布してもいいのですが、まぁ若干面倒ですね。
そこで便利なのが[Google Fonts](https://fonts.google.com/)です。『Webフォント』と呼ばれますが、インターネット上ですでに公開されているため端末のインストールなしで利用でき、どの端末からでも同じフォントで表現ができるようになります。

`app/assets/stylesheets/application.scss`でGoogle Fontsの中から`Noto Sans JP`をインポートして`body`の`font-family`に指定するだけなんですね簡単です。

```diff:app/assets/stylesheets/application.scss
  @import 'bootstrap/scss/bootstrap';
+ @import url('https://fonts.googleapis.com/css?family=Noto+Sans+JP&display=swap');

  body {
+   font-family: 'Noto Sans JP', sans-serif!important;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
  }

  footer {
    margin-top: auto;
  }
```
少し特別な書き方として、`font-family`のところで`!important`と末尾に記述してます。
`!important`はCSSの適用優先度を決めるための記述で、最優先で反映させるものに使います。つまり、他に`font-family`を記述したとしてもこいつが適用されるってことです。
Bootstrapでも`font-family`を定義してくれていたりするので、こっちを最優先にするために記述してます。

Google Fontsのサイトでお好きなフォントを探してみて適用してみてください！日本語フォントの場合は、『Language』で『Japanese』を選択すれば日本語フォントありに絞られます。『+』で使用フォントを追加するとインポートの仕方とかも教えてくれるので気軽に使えます。もっと詳しくはこちらの記事から↓
[【2019年版】Google Fontsの使い方：初心者向けに解説！](https://saruwakakun.com/html-css/basic/google-fonts)

# 後片付け
最後にコンテナを停止しておきましょう。

```
# exit
```

```
$ docker-compose down
```

# まとめ
今回は、Railsの初期設定とBootstrapのインストール、Topページのデザインをやってみました。
静的なページではありますが、コーディングした内容が反映されてどんどん変わっていくのを実感する楽しみを感じてもらえたんじゃないかと思います。

次回は今回触れていなかったModelが主役です。Modelの作成からModelに用意されているメソッドを使ってデータの作成や更新を遊んでみようと思います。

では、次回も乞うご期待！ここまでお読みいただきありがとうございました！

Next: [コーディング未経験のPO/PdMのためのRails on Dockerハンズオン vol.5 - Model and CRUD - - Qiita](https://qiita.com/at-946/items/2daa58856fc0bf6a0747)

# 本日のソースコード
- [at946/rails_on_docker_handson at vol.04](https://github.com/at946/rails_on_docker_handson/tree/vol.04)

# Reference
- [Ruby on Rails チュートリアル：実例を使って Rails を学ぼう](https://railstutorial.jp/)
- [Railsタイムゾーンまとめ - Qiita](https://qiita.com/aosho235/items/a31b895ce46ee5d3b444)
- [rails-i18n/ja.yml at master · svenfuchs/rails-i18n](https://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/ja.yml)
- [もう迷わない！CSS Flexboxの使い方を徹底解説 | Web Design Trends](https://webdesign-trends.net/entry/8148)
- [【2019年版】Google Fontsの使い方：初心者向けに解説！](https://saruwakakun.com/html-css/basic/google-fonts)

# Other Hands-on Links
- https://github.com/at946/rails_on_docker_handson/tree/master