Rails6 Devise導入 Bootstrap対応/日本語対応/名前登録まで

自作のサービスを作る際、環境構築同様毎度同じことをやるのでまとめておく。

### 事前準備
``rails s``でページ表示済み

## Deviseインストールする。

Gemfileに追加する

```Gemfile
gem "devise"
```

```
bundle install
```

```
bin/rails g devise:install
```

↑このコマンドを実行すると4つのセットアップ方法が表示されるので従う。

```config/environments/development.rb
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
```

本番用もこの時点で記述しておく

```config/environments/production.rb
# 本番環境ではhost名を指定
config.action_mailer.default_url_options = { host: 'xxxx.com' }
```

ルーティングの設定を行う

```config/routes.rb
root to: "home#index"
```

次にトップページ用のコントローラーを生成
今回はDeivseの指定に合わせて``home`` ``index``で用意。対応させていれば自由に変更OK

```
bin/rails g controller home index
```

2行のflashメッセージを追加する。
自分はbootstrapのcontainerクラス内かつ、パーシャル化させる。

```app/views/layouts/application.html.erb
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
```

Deviseのビューファイルをコピー

```
bin/rails g devise:views
```

Userモデルを作成

```
bin/rails g devise User
```

usersテーブルを作成

```
bin/rails db:migrate
```
↑要らぬ情報だけど、この時なぜか（この記事内では関係なかったため割愛）usersテーブルが既にありますというエラーが出たため``rails db:migrate:reset``で対処した。

この時点で、ログインしないとアクセスできないようにする。
もしこれをしない場合は、``rails s``で確認する際に``/users/sign_in``で確認することを忘れないよう注意。

作りたいサービスによるが、ログインしていなくてもトップページ一覧は閲覧できるようにしたい場合は、``application_controller.rb``ではなく、トップページ（今回はhome）のControllerに記載＋``index``のみ除外などの工夫をすべき？

```app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :authenticate_user!
end
```

フォームが正しく表示されているか確認

```
bin/rails s
```
↑要らぬ情報2だけど、自分はDocker使用していて、一旦``down``して再度``up``しないとルーティングエラーになった。要は色々生成しているから更新しようということ。

**これでお馴染みのフォームが生成されていればOK**

## DeviseにBootstrapを適用

必要なものをインストール（バージョンは指定しなくても。）

```
$ yarn add bootstrap@4.4.1 jquery@3.5.1 popper.js@1.16.1
```

config/webpack/environment.jsに追記

```config/webpack/environment.js
const { environment } = require('@rails/webpacker')

const webpack = require('webpack')
environment.plugins.append('Provide', new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    Popper: ['popper.js', 'default']
}))

module.exports = environment
```

app/javascript/packs/application.jsに追記

```app/javascript/packs/application.js
require("bootstrap/dist/js/bootstrap")
```

**application.cssの拡張子cssをscssに変更**

最後にapp/assets/stylesheets/application.scssに追記

```app/assets/stylesheets/application.scss
/*
 *= require_tree .
 *= require_self
 */

@import "bootstrap/scss/bootstrap";
```

**Viewを編集**

レスポンシブ対応の``viewport``を忘れずに記載しておく

```app/views/layouts/application.html.erb
..
     <%= csrf_meta_tags %>
     <%= csp_meta_tag %>
     <meta name="viewport" content="width=device-width,initial-scale=1">
..
<body>
  <header>
    <nav class="navbar navbar-expand navbar-light">
      <%= link_to "サンプル", root_path, class: 'navbar-brand' %>
      <div id="Navber">
        <ul class="navbar-nav">
          <% if user_signed_in? %>
            <li class="nav-item active">
              <%= link_to 'アカウント編集', edit_user_registration_path, class: 'nav-link' %>
            </li>
            <li class="nav-item active">
              <%= link_to 'ログアウト', destroy_user_session_path, method: :delete, class: 'nav-link' %>
            </li>
          <% else %>
            <li class="nav-item active">
              <%= link_to "新規登録", new_user_registration_path, class: 'nav-link' %>
            </li>
            <li class="nav-item active">
              <%= link_to "ログイン", new_user_session_path, class: 'nav-link' %>
            </li>
          <% end %>
        </ul>
      </div>
    </nav>
  </header>

  <div class="container">
    <p class="notice"><%= notice %></p>
    <p class="alert"><%= alert %></p>
..
```

**devise用のbootstrapのGemを追加する**
（後の日本語化のGemもこの時点で追加しておきます。）

```Gemfile
..
# 日本語化
gem 'rails-i18n', '~> 6.0'
gem 'devise-i18n'
# Bootstrap
gem 'devise-bootstrap-views', '~> 1.0'
```

**既にdeviseのviewsをinstallしている場合は、下記コマンドでbootstrap用のテンプレートに変更する
（このコマンドを使用すると、devise関連のviewにbootstrap用のclassが追加される）
（このコマンドをしないと、ページはbootstrap適用されるが、devise関連が適用されない）**

**このコマンドを打つと、既にあるviewファイルとコンフリクトを起こすが``a (all, overwrite this and all others)``で上書きすれば大丈夫

```
bin/rails g devise:views:bootstrap_templates
```

http://localhost:3000 で確認してみましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/908421/db41300c-2be0-fcfa-f530-6cf8771bd2d6.png)

このようになっていれば無事適用


## Deviseに名前も登録する

まず、usersテーブルに``name``を追加する。
``email``に適用されているユニークインデックスをnameに適用

```
rails g migration add_name_to_users name:string:uniq
```

```db/migrate/~~~~_add_name_to_users.rb
class AddNameToUsers < ActiveRecord::Migration[6.0]
  def change
    add_column :users, :name, :string
    add_index :users, :name, unique: true
  end
end
```

```
bin/rails db:migrate
```

``name``にバリデーション設定

```app/models/user.rb
..
validates :username, uniqueness: true, presence: true
```

設定ファイルで認証キーを変更

```config/initializers/devise.rb

- # config.authentication_keys = [:email]
+ config.authentication_keys = [:username]
```

**viewファイルを変更**

まずは新規登録画面
``name``を一番上にする場合は、デフォルトでは``email``に設定されている``autofocus``を変更する

```app/views/devise/registrations/new.html.erb
..
  <%= bootstrap_devise_error_messages! %>

  <!-- nameの入力欄を追加 -->
  <div class="form-group">
    <%= f.label :name %>
    <%= f.text_field :name, autofocus: true, autocomplete: 'name', class: 'form-control' %>
  </div>

  <div class="form-group">
    <%= f.label :email %>
    <%= f.email_field :email, autocomplete: 'email', class: 'form-control' %>
  </div>
..
```

StrongParameterに``name``追加

```app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    added_attrs = [ :name, :email, :password, :password_confirmation ]
    devise_parameter_sanitizer.permit :sign_up, keys: added_attrs
    devise_parameter_sanitizer.permit :account_update, keys: added_attrs
    devise_parameter_sanitizer.permit :sign_in, keys: added_attrs
  end
end

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/908421/83c6eae9-7e2f-31d8-c24e-96da6c845c92.png)

ログインも変更

```app/views/devise/sessions/new.html.erb
..
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
  <div class="form-group">
    <%= f.label :name %>
    <%= f.text_field :name, autofocus: true, autocomplete: 'name', class: 'form-control' %>
  </div>

  <div class="form-group">
    <%= f.label :email %>
    <%= f.email_field :email, autocomplete: 'email', class: 'form-control' %>
  </div>
..
```

ここまでで、新規登録/ログインともに名前込みで出来るようになったと思います

## deviseを日本語に

```config/application.rb
..
    config.load_defaults 6.0

    # 日本語
    config.i18n.default_locale = :ja
    # タイムゾーン変更
    config.time_zone = 'Asia/Tokyo'
..
```

一度サーバーを落ちしてから確認してみてください。
http://localhost:3000 
![スクリーンショット 2021-04-17 14.28.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/908421/f9efd0c7-c54d-6aa5-36b4-8d4c9e2d91f2.png)

**日本語の変更**
下記のコマンドで生成される``devise.views.ja.yml``内を編集することで変更出来る

```
bin/rails g devise:i18n:locale ja
```

- アカウント登録⇨**新規登録**
- パスワードを忘れましたか?⇨**パスワードの再設定**
の方が自然に感じると思います。



## 参考記事

- [Devise入門64のレシピ その1](https://qiita.com/shita1112/items/8b1b66705534d508cb8b)

- [[*Rails*] deviseの使い方（rails6版）](https://qiita.com/cigalecigales/items/16ce0a9a7e79b9c3974e#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB)

- [Deviseでログイン機能を追加・日本語化・Bootstrap4適用まで](https://qiita.com/take18k_tech/items/a36d77316e32a6696205)

- [deviseで作成したUserモデルにusernameカラムを追加してDBへ登録できるようにする](https://qiita.com/hz1_d/items/77e440b09a1ddbe56263)

- [【Rails】この記事を「devise 名前 ログイン」で調べたあなたへ贈る](https://qiita.com/yuki82511988/items/73659af9d1049bd1b256)