Help us understand the problem. What is going on with this article?

Deviseでログイン機能

1. はじめに

今回はDeviseを使ってログイン機能を作成していきます。
またDeviseの日本語化やBootstrap4の適用までを行っていきます。

2. 準備

$ rails new devise-sample 
$ rails g controller homes index
config/routes.rb
Rails.application.routes.draw do
  root 'homes#index'
end

3. ナビバーを追加し,レスポンシブ対応のためのmetaタグを追加

app/views/layouts/application.html.erb
 (略)
     <%= csrf_meta_tags %>
     <%= csp_meta_tag %>
     <meta name="viewport" content="width=device-width,initial-scale=1">  //追加
 (略)
  <body>
     <%= render 'shared/header' %>     //追加
     <%= yield %>
   </body>

新しくsharedフォルダと各renderファイルを作成

フラッシュメッセージ

エラーメッセージを呼び出す。

app/views/shared/_flash_messages.html.erb
<% flash.each do |msg_type, msg| %>
  <div class="alert alert-<%= msg_type %>" role="alert" id="alert">
    <a href="#" class="close" data-dismiss="alert">×</a>
    <%= msg %>
  </div>
<% end %>
app/views/homes/index.html.erb
<%= render 'shared/flash_messages' %>

ヘッダー

app/views/shared/_header.html.erb
<header>
  <nav class="navbar navbar-expand navbar-light">
    <%= link_to "Deviseサンプル", 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>

4. Gemの追加

Gemfileに以下を追加して$ bundle install

# ログイン機能に必要なGem
gem 'devise'

# 日本語化に必要なGem
gem 'rails-i18n', '~> 5.1'
gem 'devise-i18n'

# Bootstrapに必要なGem
gem 'bootstrap', '~> 4.4.1'
gem 'jquery-rails'
gem 'devise-bootstrap-views', '~> 1.0'
$ bundle install

Bootstrapの導入

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

  • application.scssから,*= require_tree .*= require_selfを削除

  • application.scss@import "bootstrap";を追加

  • スタイルも追加

app/assets/stylesheets/application.scss
@import "bootstrap";

// ログイン画面

.container-login {
  @extend .container-fluid;
  max-width: 576px;
  padding: 2rem;
}

// 「ログインしました」などのフラッシュ用スタイル

.alert-notice {
  @extend .alert-info;
}

.alert-alert {
  @extend .alert-danger;
}

application.jsに3つ追加

Bootstrapと依存関係をapplication.jsに追記する

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

補足
- Bootstrapのtooltipsやpopoverはpopper.jsに依存している
- bootstrapの依存gemにpopper_jsが指定されているため新たにインストールは不要
- コンパイルを高速化したい場合はbootstrap-sprocketsの代わりにbootstrapを指定する

Deviseの導入

Deviseをインストール(userの箇所は,任意のモデル名でOKです)

$ rails g devise:install
$ rails g devise user
$ rails db:create db:migrate

問題がなければ,$ rails sの後,http://localhost:3000からログインボタンを押せば,ログイン画面が表示されます。

スクリーンショット 2020-11-16 15.19.55.png

Deviseの日本語化

config/application.rb
module AssociationTutorial
  class Application < Rails::Application
    # 以下を追加すれば日本語に
    config.i18n.default_locale = :ja 
    # タイムゾーンも変更するなら,以下を追加
    config.time_zone = 'Asia/Tokyo'   
  end
end

サーバーを落として$ rails s
で再起動すれば日本語に変更されます。

スクリーンショット 2020-12-17 18.16.36.png

日本語訳を変更

日本語訳を変更したい場合は,次のコマンドでconfig/locales/devise.views.ja.ymlを作成し,編集すればOKです。

$ rails g devise:i18n:locale ja

例えばアカウント登録を新規登録に変更したい場合は,config/locals/devise.views.ja.ymlの該当文字を置換すればOKです。

パスワードを忘れましたか?も違和感がありますので,パスワードの再設定に置換するのがよいと思います

ログイン画面などの変更

まず,次のコマンドでビューファイルを作成します。

$ rails g devise:i18n:views
$ rails g devise:views:bootstrap_templates -f

【参考】それぞれのコマンドの最後に例えばuserをつけることで,usersディレクトリ内にファイルを作成することもできますが,その場合は,次の3つの作業を行わないと反映されません。

devise.views.ja.yml30行目のdeviseusersに変更
config/initializers/devise.rbにあるconfig.scoped_views = falseのコメントアウトを外してtrueに変更
サーバーを落として$ rails sで再起動

お好みで変えていく
例えば

<div class="container-login">
  # 元のプログラム
</div>

スクリーンショット 2020-11-17 21.05.45.png

エラーメッセージの変更

エラーメッセージの表示がいまいちなので変更するためにオーバーライドします。
app/helpers/devise_helper.rbファイルを作成し、以下を記述。

app/helpers/devise_helper.rb
module DeviseHelper
  def bootstrap_devise_error_messages!
    return "" if resource.errors.empty?

    html = ""
    resource.errors.full_messages.each do |error_message|
      html += <<-EOF
      <div class="alert alert-danger alert-dismissible" role="alert">
        <button type="button" class="close" data-dismiss="alert">
          <span aria-hidden="true">&times;</span>
          <span class="sr-only">close</span>
        </button>
        #{error_message}
      </div>
      EOF
    end
    html.html_safe
  end
end

スクリーンショット 2020-11-17 21.16.46.png

ログイン画面にもエラーメッセージを追加

app/views/devise/sessions/new.html.erb
 <div class="container-login">
   <h1><%= t('.sign_in') %></h1>
   <%= render 'shared/flash_messages' %>    //追加

   <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
  • app/views/deviseディレクトリ内のファイルのbtn btn-primarybtn btn-primary btn-blockに置換すればボタンの横幅が自然になります。

スクリーンショット 2020-11-17 21.21.35.png

バリデーション

バリデーションはフロント側にも簡単に入れられます。

  • f.email_field,f.password_fieldrequired: trueを入れることで空欄投稿できなくなります。
  • 新規登録(アカウント登録)画面では,例えば,f.password_fieldrequired: true, minlength: @minimum_password_length, maxlength: '30'を追加すれば,文字数のバリデーションを追加できます。
app/views/devise/registrations/new.html.erb
 <div class="form-group">
       <%= f.label :password %>
-      <%= f.password_field :password, autocomplete: 'current-password',
-                                      class: 'form-control' %>
+      <%= f.password_field :password, autocomplete: 'current-password',
+                                      class: 'form-control',
+                                      required: true,
+                                      minlength: @minimum_password_length,
+                                      maxlength: '30' %>

スクリーンショット 2020-11-17 21.33.29.png

_links.html.erbを編集して,一番下のリンクをボタンにしてみます。

app/views/devise/shared/_links.html.erb
<hr class="border-dark my-5">
<div class="form-group">
  <%- if controller_name != 'sessions' %>
    <%= link_to t(".sign_in"), new_session_path(resource_name), class: 'btn btn-info btn-block' %><br />
  <% end -%>

  <%- if devise_mapping.registerable? && controller_name != 'registrations' %>
    <%= link_to t(".sign_up"), new_registration_path(resource_name), class: 'btn btn-info btn-block' %><br />
  <% end -%>

  <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
    <%= link_to t(".forgot_your_password"), new_password_path(resource_name), class: 'btn btn-secondary btn-block' %><br />
  <% end -%>

  <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
    <%= link_to t('.didn_t_receive_confirmation_instructions'), new_confirmation_path(resource_name), class: 'btn btn-secondary btn-block' %><br />
  <% end -%>

  <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
    <%= link_to t('.didn_t_receive_unlock_instructions'), new_unlock_path(resource_name), class: 'btn btn-secondary btn-block' %><br />
  <% end -%>

  <%- if devise_mapping.omniauthable? %>
    <%- resource_class.omniauth_providers.each do |provider| %>
      <%= link_to t('.sign_in_with_provider', provider: OmniAuth::Utils.camelize(provider)), omniauth_authorize_path(resource_name, provider), class: 'btn btn-info btn-block' %><br />
    <% end -%>
  <% end -%>
</div>

スクリーンショット 2020-11-17 21.37.44.png

さらに,リンクのログイン,新規登録(アカウント登録)を次のように変更してみます

# 上2つを次に置き換え

  <%- if controller_name != 'sessions' %>
    <%= link_to "アカウントをお持ちの方", new_session_path(resource_name), class: 'btn btn-info btn-block' %><br />
  <% end -%>

  <%- if devise_mapping.registerable? && controller_name != 'registrations' %>
    <%= link_to "アカウントをお持ちでない方", new_registration_path(resource_name), class: 'btn btn-info btn-block' %><br />
  <% end -%>
app/views/devise/registrations/edit.html.erb
<!-- ここから -->
  <p><%= t('.unhappy') %>
    ? <%= link_to t('.cancel_my_account'), registration_path(resource_name), data: {confirm: t('.are_you_sure')}, method: :delete %>
    .</p>

  <%= link_to t('.back'), :back %>
<!-- ここまでを次に置き換える -->

  <hr class="devise-link my-5">
  <div class="form-group">
    <%= link_to "トップページ", root_path, class: 'btn btn-info btn-block mb-4' %>
    <%= link_to t('.cancel_my_account'), registration_path(resource_name), data: {confirm: t('.are_you_sure')}, method: :delete, class: 'btn btn-danger btn-block' %>
  </div>

スクリーンショット 2020-11-17 21.47.19.png

これで一応単純なスタイルは完成です。
もし間違っているところがあればご教授いただけると幸いです。

mat827
現在は転職活動中です。 学んだことやプロダクトをアウトプットしていきます。 よろしくお願いします!
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away