[Rails] deviseのフラッシュメッセージにBootstrap4を適用する

## TL;DR
deviseのWikiをもとに、Bootstrap4をフラッシュメッセージに適用してみました。
[How To: Integrate I18n Flash Messages with Devise and Bootstrap](https://github.com/plataformatec/devise/wiki/How-To:-Integrate-I18n-Flash-Messages-with-Devise-and-Bootstrap)

適用前（左）と適用後（右）
![before_after.png](https://qiita-image-store.s3.amazonaws.com/0/82132/f0eac44d-7576-31f8-aef8-973f5d9b40f4.png)

## 前提

以下のQiita記事をもとに作成したソースコードをもとにしています。(わかりやすい記事ありがとうございます！)
[[*Rails*] deviseの使い方（rails5版）](https://qiita.com/cigalecigales/items/f4274088f20832252374)
「deviseの導入」まで終わった状態が記事執筆前の状態です。（ただし、twitter-omniauthは設定していません）

## 動作環境

- OS: macOS Sierra 10.12.6
- Docker 18.06.0-ce (client, serverともに)

Mac上で以下の設定のコンテナを動かし、動作確認しました。

- Ruby version: 2.4.1
- Rails version: 5.1.4
- devise version: 4.4.3

ブラウザ

- Google Chrome: 68.0.3440.106（Official Build）（64 ビット）

## やったこと

1. Bootstrap4のインストール
2. deviseのフラッシュメッセージ用のビューを作成
3. deviseのエラーメッセージへの対応
4. カスタムクラスを定義

ソースコードはこちら。
https://github.com/ftnext/rails_devise_practice/tree/694675a8a66513b616f7d126a7b225a36817c203

## Bootstrap4のインストール

#### gemをインストール

* bootstrap (4.1.3。執筆時最新)
* autoprefixer-rails (6.0.3)
* jquery-rails (4.3.3。執筆時最新)

Bootstrap4が使いたかったので、bootstrap-sassではなくbootstrapを使用[^1]。  
bootstrapに依存してインストールされたautoprefixer-railsでは以下のエラーが出ました。
コンテナに入っているNode(v0.10.29)で動くように、依存関係を満たす最低バージョンにautoprefixer-railsのバージョンを下げて対応。[^2]
>RuntimeError in Pages#index
>Showing /myapp/app/views/layouts/application.html.erb where line #7 raised:
>Autoprefixer doesn’t support Node v0.10.29. Update it.
>`<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>`

#### Bootstrapが使えるように設定

参考：https://github.com/twbs/bootstrap-rubygem#a-ruby-on-rails

1. app/assets/stylesheets/application.scssで`@import "bootstrap";`
    - `app/assets/stylesheets/application.css`がある場合は、拡張子が.scssになるように名前を変える
2. app/assets/javascripts/application.jsにて3行追加

```app/assets/javascripts/application.js
//= require jquery3
//= require popper
//= require bootstrap-sprockets
```

(bootstrap-sprocketsはデバッグ用とのこと)

## deviseのフラッシュメッセージ用のビューを作成

参照しているWikiの「Flash Messages For the Site」の部分。
フラッシュメッセージ用のパーシャルを作る。

Wikiのコードの理解には以下の記事に助けられました。ありがとうございます！
https://qiita.com/mikan3rd/items/ca783769c959a16cc999#%E5%85%B7%E4%BD%93%E7%9A%84%E3%81%AA%E4%BD%BF%E7%94%A8%E4%BE%8B
>flashには標準で　notice（動作成功時）とalert（動作失敗時）の2つのキーを生成してくれるため、両方に適用できるようにeachメソッドを使ってkeyとvalueを取り出しています。

パーシャルではalert-notice、alert-alertの2クラスを設定しているようです。

## deviseのエラーメッセージへの対応

参照しているWikiの「Flash Messages For Devise」の部分。
エラーメッセージを扱うメソッドdevise_error_messages!をオーバーライドして対応するそうです。
deviseのエラーメッセージにBootstrapのalert-dangerクラスを指定。

htmlでは閉じるボタンを押すと消えるフラッシュメッセージを設定しているようです。[^3]
https://www.w3schools.com/bootstrap4/bootstrap_alerts.asp
`&times;`は閉じるボタンのHTMLエンティティだそうです。
>Tip: &times; (×) is an HTML entity that is the preferred icon for close buttons, rather than the letter "x".

途中経過はこちら。
![intermidiate_state.png](https://qiita-image-store.s3.amazonaws.com/0/82132/16d0efbb-a930-f779-c919-018221c05066.png)

登録時のエラーメッセージはBootstrapのスタイルが適用されています。
alert-notice（ログアウト後のメッセージ）、alert-alert（ログイン失敗メッセージ）の2クラスは
Bootstrapにないクラス[^4]なのでスタイルが適用されていません。

## カスタムクラスを定義

Wikiの「CSS For Flash Messages」を参考に、alert-notice、alert-alertの2クラスにスタイルを設定していきます。

```app/assets/stylesheets/application.scss
@import "bootstrap";
@import "custom";  // 追加
```

```app/assets/stylesheets/custom.css.scss
$ng_alert_bg_color: #f2dede;
$ng_alert_border_color: #eed3d7;
$ng_alert_color: #b94a48;
$ok_alert_bg_color: #dff0d8;
$ok_alert_border_color: #d6e9c6;
$ok_alert_color: #468847;
/* flash */
.alert-alert {
  background-color: $ng_alert_bg_color;
  border-color: $ng_alert_border_color;
  color: $ng_alert_color;
  text-align: left;
}
.alert-notice {
  background-color: $ok_alert_bg_color;
  border-color: $ok_alert_border_color;
  color: $ok_alert_color;
  text-align: left;
}
```

alert-noticeとalert-alertにもスタイルが適用されました！[^5]
![after.png](https://qiita-image-store.s3.amazonaws.com/0/82132/7a74ee6a-4638-3709-ecd7-aff2f932379e.png)

bootstrap -> custom の順でimportされるので、custom.css.scssでalert-dangerクラスの上書きも可能でした。

## 終わりに

deviseはWikiが充実していて、素振り材料には事欠かない印象です。
今後も気になるトピックについて手を動かしていきます。

## 脚注

[^1]: Bootstrap 4 ruby gem for Ruby on Rails (Sprockets) and Hanami (formerly Lotus).For Sass versions of Bootstrap 3 and 2 see bootstrap-sass instead. (https://github.com/twbs/bootstrap-rubygem より引用)
[^2]: コンテナにv0.10.29よりも新しいNodeを入れる方法については宿題事項です。(`apt-get install nodejs`ではない方法でのインストールを試す予定)
[^3]: ここのアニメーションにjQueryが必要と理解しました。
[^4]: Alerts are created with the .alert class, followed by one of the contextual classes .alert-success, .alert-info, .alert-warning, .alert-danger, .alert-primary, .alert-secondary, .alert-light or .alert-dark: (https://www.w3schools.com/bootstrap4/bootstrap_alerts.asp より引用)
[^5]: _message.html.erbに閉じるボタンのコードが落ちていることに気づき、この後付け加えました。(冒頭の画像の状態が最新のソースコードです)