【Rails6】deviseで独自カラムを追加して使用する方法 ②

## これまで
これまでに、deviseのインストールと、Userモデルの作成を行いました。

今回は、ビューのカスタマイズを行っていきたいと思います。

▽前回の記事はこちら▽
[【Rails6】deviseで独自カラムを追加して使用する方法 ①](https://qiita.com/kamataku/items/e54150357cd51e1b3a40)

## ① View 作成
View を追加する`rails g devise:views` コマンドを実行

```sh
$ rails g devise:views
Running via Spring preloader in process 1254
      invoke  Devise::Generators::SharedViewsGenerator
      create    app/views/devise/shared #フォルダ
      create    app/views/devise/shared/_error_messages.html.erb #エラーメッセージ用パーシャル
      create    app/views/devise/shared/_links.html.erb #リンク用パーシャル
      invoke  form_for
      create    app/views/devise/confirmations #フォルダ
      create    app/views/devise/confirmations/new.html.erb #認証メール再送信画面
      create    app/views/devise/passwords #フォルダ
      create    app/views/devise/passwords/edit.html.erb #パスワード変更画面
      create    app/views/devise/passwords/new.html.erb #パスワード初期化メール送信画面
      create    app/views/devise/registrations #フォルダ
      create    app/views/devise/registrations/edit.html.erb #ユーザ情報変更画面
      create    app/views/devise/registrations/new.html.erb #ユーザ新規登録画面
      create    app/views/devise/sessions #フォルダ
      create    app/views/devise/sessions/new.html.erb #ログイン画面
      create    app/views/devise/unlocks
      create    app/views/devise/unlocks/new.html.erb #ロック解除メール再送信画面
      invoke  erb
      create    app/views/devise/mailer #フォルダ
      create    app/views/devise/mailer/confirmation_instructions.html.erb #アカウント認証メール
      create    app/views/devise/mailer/email_changed.html.erb #メールアドレス変更完了メール
      create    app/views/devise/mailer/password_change.html.erb #パスワード変更完了メール
      create    app/views/devise/mailer/reset_password_instructions.html.erb #パスワード初期化メール
      create    app/views/devise/mailer/unlock_instructions.html.erb #ロック解除メール
```

上記コマンドで、ひと通り devise 用の View ( 各ファイルに `#` でファイルの用途を記載しました ) が生成されます。

今から、それぞれの View をカスタマイズしていきます。

## ② View の構成
devise View 用のレイアウトテンプレートを用意し、画面を表示させようと思います。
![20210507_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/613022/e8028cf9-d774-3c03-8133-d9e894b365bd.png)

## ③ レイアウトテンプレート 作成
`/app/views/layouts` 内に `devise.html.erb` という名前のファイルを作成します。

```ruby:devise.html.erb
<!DOCTYPE html>
<html lang="ja-JP" dir="ltr">
  <head>
    <!--    Meta_Tags-->
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <!--    Page_Title-->
    <title><%= @page_title%> | Sample</title>
    <!--    Stylesheets-->
    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <!--    メッセージ表示用-->
    <% flash.each do |message_type, message| %>
      <p><%= message %></p>
    <% end %>

    <%= yield %>
    
    <!--    JavaScripts-->
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
    
  </body>
</html>
```

※ 今回分かりやすくするように `devise.html.erb` というファイル名にしましたが、決まりはありません。

## ④ app/views/devise/shared パーシャル カスタマイズ
今回は日本語表記への変更のみを行います。

```ruby:_links.html.erb_編集前
<%- if controller_name != 'sessions' %>
  <%= link_to "Log in", new_session_path(resource_name) %><br />
<% end %>

<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
  <%= link_to "Sign up", new_registration_path(resource_name) %><br />
<% end %>

<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
  <%= link_to "Forgot your password?", new_password_path(resource_name) %><br />
<% end %>

<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
  <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %><br />
<% end %>

<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
  <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br />
<% end %>

<%- if devise_mapping.omniauthable? %>
  <%- resource_class.omniauth_providers.each do |provider| %>
    <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %><br />
  <% end %>
<% end %>
```

```ruby:_links.html.erb_編集後
<%- if controller_name != 'sessions' %>
  <%= link_to "ログイン", new_session_path(resource_name) %><br />
<% end %>

<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
  <%= link_to "ユーザ登録", new_registration_path(resource_name) %><br />
<% end %>

<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
  <%= link_to "パスワードを忘れた場合", new_password_path(resource_name) %><br />
<% end %>

<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
  <%= link_to "確認メールが届かない場合", new_confirmation_path(resource_name) %><br />
<% end %>

<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
  <%= link_to "ロック解除メールが届かない場合", new_unlock_path(resource_name) %><br />
<% end %>

<%- if devise_mapping.omniauthable? %>
  <%- resource_class.omniauth_providers.each do |provider| %>
    <%= link_to "#{OmniAuth::Utils.camelize(provider)} でログイン", omniauth_authorize_path(resource_name, provider) %><br />
  <% end %>
<% end %>
```

※ここでは `_error_messages.html.erb` のカスタマイズは行いませんが、必要に応じて行なってください。

## ⑤ app/views/devise/confirmations カスタマイズ
今回は日本語表記への変更のみを行います。

```ruby:new.html.erb_編集前
<h2>Resend confirmation instructions</h2>

<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
  <%= render "devise/shared/error_messages", resource: resource %>

  <div class="field">
    <%= f.label :email %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email", value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %>
  </div>

  <div class="actions">
    <%= f.submit "Resend confirmation instructions" %>
  </div>
<% end %>

<%= render "devise/shared/links" %>
```

```ruby:new.html.erb_編集後
<h2>確認メールの再送</h2>

<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
  <%= render "devise/shared/error_messages", resource: resource %>

  <div class="field">
    <%= f.label :メールアドレス %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email", value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %>
  </div>

  <div class="actions">
    <%= f.submit "確認メール再送信" %>
  </div>
<% end %>

<%= render "devise/shared/links" %>
```

## ⑥ app/views/devise/passwords カスタマイズ
今回は日本語表記への変更のみを行います。

`edit.html.erb`

```ruby:edit.html.erb_編集前
<h2>Change your password</h2>

<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %>
  <%= render "devise/shared/error_messages", resource: resource %>
  <%= f.hidden_field :reset_password_token %>

  <div class="field">
    <%= f.label :password, "New password" %><br />
    <% if @minimum_password_length %>
      <em>(<%= @minimum_password_length %> characters minimum)</em><br />
    <% end %>
    <%= f.password_field :password, autofocus: true, autocomplete: "new-password" %>
  </div>

  <div class="field">
    <%= f.label :password_confirmation, "Confirm new password" %><br />
    <%= f.password_field :password_confirmation, autocomplete: "new-password" %>
  </div>

  <div class="actions">
    <%= f.submit "Change my password" %>
  </div>
<% end %>

<%= render "devise/shared/links" %>

```

```ruby:edit.html.erb_編集後
<h2>パスワードの変更</h2>

<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %>
  <%= render "devise/shared/error_messages", resource: resource %>
  <%= f.hidden_field :reset_password_token %>

  <div class="field">
    <%= f.label :password, "新しいパスワード" %><br />
    <% if @minimum_password_length %>
      <em>(<%= @minimum_password_length %> characters minimum)</em><br />
    <% end %>
    <%= f.password_field :password, autofocus: true, autocomplete: "new-password" %>
  </div>

  <div class="field">
    <%= f.label :password_confirmation, "新しいパスワード確認" %><br />
    <%= f.password_field :password_confirmation, autocomplete: "new-password" %>
  </div>

  <div class="actions">
    <%= f.submit "パスワードの変更" %>
  </div>
<% end %>

<%= render "devise/shared/links" %>

```

`new.html.erb`

```ruby:new.html.erb_編集前
<h2>Forgot your password?</h2>

<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %>
  <%= render "devise/shared/error_messages", resource: resource %>

  <div class="field">
    <%= f.label :email %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
  </div>

  <div class="actions">
    <%= f.submit "Send me reset password instructions" %>
  </div>
<% end %>

<%= render "devise/shared/links" %>
```

```ruby:new.html.erb_編集後
<h2>パスワードを忘れた場合</h2>

<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %>
  <%= render "devise/shared/error_messages", resource: resource %>

  <div class="field">
    <%= f.label :メールアドレス %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
  </div>

  <div class="actions">
    <%= f.submit "パスワードの初期化手順を送信" %>
  </div>
<% end %>

<%= render "devise/shared/links" %>
```
## ⑦ app/views/devise/registrationss カスタマイズ
今回は 日本語表記への変更 ・ 独自カラム項目の追加 を行います。

`edit.html.erb`

```ruby:edit.html.erb_編集前
<h2>Edit <%= resource_name.to_s.humanize %></h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
  <%= render "devise/shared/error_messages", resource: resource %>

  <div class="field">
    <%= f.label :email %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
  </div>

  <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
    <div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
  <% end %>

  <div class="field">
    <%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
    <%= f.password_field :password, autocomplete: "new-password" %>
    <% if @minimum_password_length %>
      <br />
      <em><%= @minimum_password_length %> characters minimum</em>
    <% end %>
  </div>

  <div class="field">
    <%= f.label :password_confirmation %><br />
    <%= f.password_field :password_confirmation, autocomplete: "new-password" %>
  </div>

  <div class="field">
    <%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
    <%= f.password_field :current_password, autocomplete: "current-password" %>
  </div>

  <div class="actions">
    <%= f.submit "Update" %>
  </div>
<% end %>

<h3>Cancel my account</h3>

<p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %></p>

<%= link_to "Back", :back %>
```

```ruby:edit.html.erb_編後
<h2>ユーザ情報変更 <%= resource_name.to_s.humanize %></h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
  <%= render "devise/shared/error_messages", resource: resource %>

  <div class="field">
    <%= f.label :メールアドレス %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
  </div>

  <div class="field">
    <%= f.label :ユーザ名 %><br />
    <%= f.text_field :user_code %>
  </div>

  <div class="field">
    <%= f.label :姓 %><br />
    <%= f.text_field :user_last_name, autocomplete: "last_name" %>
  </div>

  <div class="field">
    <%= f.label :名 %><br />
    <%= f.text_field :user_first_name, autocomplete: "first_name" %>
  </div>

  <!-- メールの認証状況の表示_未確認の場合 -->
  <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
    <div>メール認証を完了してください : <%= resource.unconfirmed_email %></div>
  <% end %>
  <!-- メールの認証状況の表示_未確認の場合(END) -->

  <div class="field">
    <%= f.label :新しいパスワード %> <i>(変更しない場合は空白)</i><br />
    <%= f.password_field :password, autocomplete: "new-password" %>
    <% if @minimum_password_length %>
      <br />
      <em><%= @minimum_password_length %> characters minimum</em>
    <% end %>
  </div>

  <div class="field">
    <%= f.label :新しいパスワード確認 %><br />
    <%= f.password_field :password_confirmation %>
  </div>

  <div class="field">
    <%= f.label :現在のパスワード %><br />
    <%= f.password_field :current_password, autocomplete: "current-password" %>
  </div>

  <div class="actions">
    <%= f.submit "更新" %>
  </div>
<% end %>

<h3>退会</h3>

<p>退会処理を行うと元に戻せません。 <%= button_to "退会する", registration_path(resource_name), data: { confirm: "退会処理を行います" }, method: :delete %></p>

<%= link_to "戻る", :back %>
```

`new.html.erb`

```ruby:new.html.erb_編集前
<h2>Sign up</h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= render "devise/shared/error_messages", resource: resource %>

  <div class="field">
    <%= f.label :email %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
  </div>

  <div class="field">
    <%= f.label :password %>
    <% if @minimum_password_length %>
    <em>(<%= @minimum_password_length %> characters minimum)</em>
    <% end %><br />
    <%= f.password_field :password, autocomplete: "new-password" %>
  </div>

  <div class="field">
    <%= f.label :password_confirmation %><br />
    <%= f.password_field :password_confirmation, autocomplete: "new-password" %>
  </div>

  <div class="actions">
    <%= f.submit "Sign up" %>
  </div>
<% end %>

<%= render "devise/shared/links" %>
```

```ruby:new.html.erb_編集後
<h2>ユーザ登録</h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= render "devise/shared/error_messages", resource: resource %>

  <div class="field">
    <%= f.label :メールアドレス %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
  </div>

  <div class="field">
    <%= f.label :ユーザ名 %><br />
    <%= f.text_field :user_code %>
  </div>

  <div class="field">
    <%= f.label :姓 %><br />
    <%= f.text_field :user_last_name, autocomplete: "last_name" %>
  </div>

  <div class="field">
    <%= f.label :名 %><br />
    <%= f.text_field :user_first_name, autocomplete: "first_name" %>
  </div>

  <div class="field">
    <%= f.label :パスワード %>
    <% if @minimum_password_length %>
    <em>(<%= @minimum_password_length %>文字以上)</em>
    <% end %><br />
    <%= f.password_field :password, autocomplete: "new-password" %>
  </div>

  <div class="field">
    <%= f.label :パスワード確認 %><br />
    <%= f.password_field :password_confirmation, autocomplete: "new-password" %>
  </div>

  <div class="actions">
    <%= f.submit "ユーザ登録" %>
  </div>
<% end %>

<%= render "devise/shared/links" %>
```
## ⑧ app/views/devise/sessions カスタマイズ
今回は 日本語表記への変更 ・ ログインをメールアドレスから独自カラムへ変更 を行います。

```ruby:new.html.erb_編集前
<h2>Log in</h2>

<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
  <div class="field">
    <%= f.label :email %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
  </div>

  <div class="field">
    <%= f.label :password %><br />
    <%= f.password_field :password, autocomplete: "current-password" %>
  </div>

  <% if devise_mapping.rememberable? %>
    <div class="field">
      <%= f.check_box :remember_me %>
      <%= f.label :remember_me %>
    </div>
  <% end %>

  <div class="actions">
    <%= f.submit "Log in" %>
  </div>
<% end %>

<%= render "devise/shared/links" %>
```

```ruby:new.html.erb_編集後
<h2>ログイン</h2>

<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
  <div class="field">
    <%= f.label :ユーザ名 %><br />
    <%= f.text_field :user_code, autofocus: true, autocomplete: "user_code" %>
  </div>

  <div class="field">
    <%= f.label :パスワード %><br />
    <%= f.password_field :password, autocomplete: "current-password" %>
  </div>

  <% if devise_mapping.rememberable? %>
    <div class="field">
      <%= f.check_box :ログイン情報を記憶しておく %>
      <%= f.label :ログイン情報を記憶しておく %>
    </div>
  <% end %>

  <div class="actions">
    <%= f.submit "ログイン" %>
  </div>
<% end %>

<%= render "devise/shared/links" %>
```

## ⑨ app/views/devise/unlocks カスタマイズ
今回は日本語表記への変更のみを行います。

```ruby:new.html.erb
<h2>ロック解除メール再送</h2>

<%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %>
  <%= render "devise/shared/error_messages", resource: resource %>

  <div class="field">
    <%= f.label :メールアドレス %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
  </div>

  <div class="actions">
    <%= f.submit "ロック解除メール再送信" %>
  </div>
<% end %>

<%= render "devise/shared/links" %>
```

## ⑩ app/views/devise/mailer メールテンプレート カスタマイズ
今回は日本語表記への変更のみを行います。

`confirmation_instructions.html.erb`

```ruby:confirmation_instructions.html.erb_変更前
<p>Welcome <%= @email %>!</p>

<p>You can confirm your account email through the link below:</p>

<p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></p>
```

```ruby:confirmation_instructions.html.erb_変更後
<p>ようこそ <%= @resource.user_last_name %> 様</p>

<p>下記のURLから登録を完了させてください。</p>

<p><%= link_to '登録', confirmation_url(@resource, confirmation_token: @token) %></p>
```

`email_changed.html.erb`

```ruby:email_changed.html.erb_編集前
<p>Hello <%= @email %>!</p>

<% if @resource.try(:unconfirmed_email?) %>
  <p>We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.</p>
<% else %>
  <p>We're contacting you to notify you that your email has been changed to <%= @resource.email %>.</p>
<% end %>
```

```ruby:email_changed.html.erb_編集後
<p><%= @resource.user_last_name %> 様</p>

<% if @resource.try(:unconfirmed_email?) %>
  <p><%= @resource.unconfirmed_email %>にメールアドレスが変更されました。</p>
<% else %>
  <p><%= @resource.email %>にメールアドレスが変更されました。</p>
<% end %>
```

`password_change.html.erb`

```ruby:password_change.html.erb_編集前
<p>Hello <%= @resource.email %>!</p>

<p>We're contacting you to notify you that your password has been changed.</p>
```

```ruby:password_change.html.erb_編集後
<p><%= @resource.user_last_name %> 様</p>

<p>パスワードが変更されました。</p>
```

`reset_password_instructions.html.erb`

```ruby:reset_password_instructions.html.erb_編集前
<p>Hello <%= @resource.email %>!</p>

<p>Someone has requested a link to change your password. You can do this through the link below.</p>

<p><%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %></p>

<p>If you didn't request this, please ignore this email.</p>
<p>Your password won't change until you access the link above and create a new one.</p>
```

```ruby:reset_password_instructions.html.erb_編集後
<p><%= @resource.user_last_name %> 様</p>

<p>パスワードの初期化メールが送信されました。下記のURLからパスワードの再設定が行えます。</p>

<p><%= link_to 'パスワードの再設定', edit_password_url(@resource, reset_password_token: @token) %></p>

<p>お心当たりのないメールはお手数ですが削除をお願いいたします。 </p>
<p>上記のURLからパスワードの再設定が行われるまで、パスワードは変更されません。</p>
```

`unlock_instructions.html.erb`

```ruby:unlock_instructions.html.erb_編集前
<p>Hello <%= @resource.email %>!</p>

<p>Your account has been locked due to an excessive number of unsuccessful sign in attempts.</p>

<p>Click the link below to unlock your account:</p>

<p><%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %></p>
```

```ruby:unlock_instructions.html.erb_編集後
<p><%= @resource.user_last_name %> 様</p>

<p>ログインに失敗した回数が多いため、アカウントがロックされました。</p>

<p>アカウントのロック解除するには、下記のURLをクリックしてください。</p>

<p><%= link_to 'ロックの解除', unlock_url(@resource, unlock_token: @token) %></p>
```

ここまで行うと、ビューのカスタマイズが反映されます。

長くなりましたので、記事を分けてご紹介しようと思います。
次回は、コントローラ・モデル・ルーティングのカスタマイズを行っていきたいと思います。

▽次の記事はこちら▽
[【Rails6】deviseで独自カラムを追加して使用する方法 ③](https://qiita.com/kamataku/items/1b550f97cc53195b01bf)