[勉強メモ]rails deviseを使った認証


deviseとは

  • ログイン認証機能を提供するgem
  • 認証周りとかユーザの編集や削除機能も提供している

devise使うと何ができる?

  • アカウント作成
  • ログイン
  • ログアウト
  • パスワード変更
  • アカウントの凍結(一定回数以上ログインの失敗時など)

deviseのセットアップ

Gemfileへ記述

Gemfileに下記を追記

Gemfile
# Authenticate by devise
gem "devise"
gem "devise-i18n"
  • devise-i18n
    • バリデーションエラー時のメッセージとかを日本語化するために使う(後述)

コマンド実行

機能をインストール

コマンド実行
bundle install

モデルとかマイグレーション、ビューを作成

rails g devise:install #deviseのインストール
rails g devise user #モデルを作成
rake db:migrate #userテーブルを作成
rails g devise:views #ビューの作成

コマンドを実行するとメッセージが出力されるので書いてある通りに付け加える
```console
Some setup you must do manually if you haven't yet:

  1. Ensure you have defined default url options in your environments files. Here
    is an example of default_url_options appropriate for a development environment
    in config/environments/development.rb:

    config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

    In production, :host should be set to the actual host of your application.

  2. Ensure you have defined root_url to something in your config/routes.rb.
    For example:

    root to: "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
    For example:

    <%= notice %>


    <%= alert %>

  4. You can copy Devise views (for customization) to your app by running:

    rails g devise:views
    ```

config/environments/development.rb:に追記

config/environments/development.rb
  # Device gem settings
  config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

routes.rbに追記

routes.rb
Rails.application.routes.draw do
  devise_for :users
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html  
  root "home#index"
end

app/views/layouts/application.html.erb.へアラートを表示したい場所に下記追記

app/views/layouts/application.html.erb.
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield :title%></title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <%= render partial: "shared/header"%>   
    <div class="container-fluid">
      <% flash.each do |message_type, message| %>
        <%= tag.div message,class:"alert alert-#{message_type}" %>
      <% end %>
      #追記箇所#
      <p class="notice"><%= notice %></p>
      <p class="alert"><%= alert %></p>
      #追記終わり#
      <div class="row" id="all-body">
        <div class="col-sm-12 col-md-12 content">
          <%= yield %>
        </div>
      </div>
    </div>
    <%= render partial: "shared/footer"%>
    <%= debug(params) if Rails.env.development? %>
  </body>
</html>

マイグレーション

先ほどのコマンドでマイグレーションファイルが作成されている

マイグレーションファイル
# frozen_string_literal: true

class AddDeviseToUsers < ActiveRecord::Migration[5.2]
  #drop_table :users
  create_table :users
  def self.up
    change_table :users do |t|
      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
       t.integer  :sign_in_count, default: 0, null: false
       t.datetime :current_sign_in_at
       t.datetime :last_sign_in_at
       t.string   :current_sign_in_ip
       t.string   :last_sign_in_ip

      ## Confirmable
       t.string   :confirmation_token
       t.datetime :confirmed_at
       t.datetime :confirmation_sent_at
       t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
       t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
       t.string   :unlock_token # Only if unlock strategy is :email or :both
       t.datetime :locked_at


      # Uncomment below if timestamps were not included in your original model.
       #t.timestamps null: false
    end

    add_index :users, :email,                unique: true
    add_index :users, :reset_password_token, unique: true
    add_index :users, :confirmation_token,   unique: true
    add_index :users, :unlock_token,         unique: true
  end

  def self.down
    # By default, we don't want to make any assumption about how to roll back a migration when your
    # model already existed. Please edit below which fields you would like to remove in this migration.
    raise ActiveRecord::IrreversibleMigration
  end
end

今回ユーザ登録画面でユーザ名を使いたかったので、rails g migrateでnameカラムを追加

rails g migration AddNameToUser name:string
rails db:migrate

ユーザ名を保存できるようにcontrollers/application_controller.rbに追記
-(ToDo)どのような処理をしているのか調べておく
```ruby::controllers/application_controller.rb
class ApplicationController < ActionController::Base
include SessionsHelper
before_action :configure_permitted_parameters, if: :devise_controller?

protected
def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
    devise_parameter_sanitizer.permit(:account_update, keys: [:name])
end

end
```

Viewの作成

コマンドを実行してviewを作成する

rails g devise:view User

作成されたViewを変更できるようにconfig/initializers/devise.rbを下記に変更
ruby:config/initializers/devise.rb
config.scoped_views = true

アラートの日本語化

config/application.rbに下記追記

config/application.rb
config.i18n.default_locale = :ja

viewをもう一回作り直す

rails g devise:i18n:locale ja
rails g devise:i18n:locale en
rm config/locales/devise.en.yml

試してみた

(注意)画像は下手くそなりにcssいじった結果の画面です。
初期表示画面

バリデーション引っかかると

deviseで作成したViewに任意のパスでアクセスしたい

  • deviseで生成したviewに任意のパスを指定できるようにしたい時は下記を記述
  • devise_scopeブロック内でrouteを宣言することで任意のルートを設定可能
routes.rb
Rails.application.routes.draw do
  devise_for :users
  devise_scope :user do
    get     'signup' => 'devise/registrations#new' 
    get     'login'  => 'devise/sessions#new'     
    post    'login'  => 'devise/sessions#create'  
    delete 'logout'  => 'devise/sessions#destroy' 
  end
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html  
  root "muscle#index"
end

deviseが提供するヘルパーメソッド

メソッド名 機能
before_action :authenticate_user! ログイン済みのユーザに対してアクセスを許可する
user_signed_in? ログイン済みユーザーか?
current_user ログインしているユーザの情報を取得
user_session ユーザーのセッション情報にアクセス

まとめ

  • railsチュートリアルでは認証周りは自作しているが、deviseを使うことでより簡単に実装ができる
  • css周りは既存のviewに対してclass指定したりしてアレンジする
  • sessionの保持時間をいじれるか調べて実装したい