Tatehitoの技術メモ

ソフトウェアエンジニアです。いろいろ書きます。

【Rails】簡単に認証機能がつくれるgem『devise』を試す

はじめに

つぎにつくる予定のWebアプリでは、認証(ログイン)機能を実装しようと思っています。そこで認証機能を実装するためのgemで有名な『devise』の最低限の動作確認をしてみました。

環境は以下の通りです💡

  • Ruby 2.6.3
  • Rails 6.0.0
  • devise 4.7.1 (現時点の最新バージョン)

完成イメージ

この記事の通りに進めると、以下のサンプルアプリが完成します。

トップページ(未ログイン状態)

f:id:tatehito-st:20191012143845p:plain:w300

ログイン画面

f:id:tatehito-st:20191012141241p:plain:w200

ログインするとユーザーページ表示

f:id:tatehito-st:20191012151729p:plain:w300

トップページ(ログイン状態)

f:id:tatehito-st:20191012143859p:plain:w300

ログアウトすると元に戻ります。

f:id:tatehito-st:20191012143845p:plain:w300

実装

1.rails newする

Rails6.0.0でアプリを新規作成します。

rails _6.0.0_ new gem-devise-sample

トップページが表示されることを確認します。

f:id:tatehito-st:20191012120812p:plain

2.devise をインストールする

Gemfileに以下を記述し、bundle install

# Gemfile

gem 'devise'

続けて、以下のコマンドでdeviseの設定ファイルを作成します。

$ rails g devise:install

3.devise対応のUserモデルを生成する

Userモデルをつくります。以下のコマンドでdevise対応のUserモデルを生成。

$ rails g devise User

以下のマイグレーションファイルが生成されるので、rails db:migrateでマイグレーションを実行。 コメントアウトされているカラムがあるが、今回は最低限の動作確認のみのため、そのままにしておきます。

# frozen_string_literal: true

class DeviseCreateUsers < ActiveRecord::Migration[6.0]
  def change
    create_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


      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
end

この時点で、http://localhost:3000/users/sign_inを開くと最低限のログインページができています。

f:id:tatehito-st:20191012141241p:plain:w200

しかし、この状態だと認証後のリダイレクト先ページがRailsのデフォルトページ(Yay! You’re on Rails!の画面)になっているので、 リダイレクト先ページをユーザー個人のプロフィールページに変更します。

4.トップページをつくる

Pagesコントローラーをindex、showアクションつきで生成。

$ rails g controller Pages index show

ルーティングを設定をします。rootを先ほど生成したpages#indexに。なお、devise_for :usersはdevise対応のUserモデルを生成した時点で自動で設定されます。

# route.rb

Rails.application.routes.draw do
  root 'pages#index'
  get 'pages/show'
  devise_for :users
end

トップページのビューを編集します。今回は、ログイン状態によって、表示するリンクが切り替わるようにしたいと思います。user_signed_in?でログイン状態を判定し、表示するリンクを切り替えます。

routes.rbに設定されたdevise_for :usersにより、‘new_user_session_path‘や‘destroy_user_session_path‘など、devise用の名前付きルートが使えるようになっているので、その名前付きルートを使ってリンクを記述します。

<!-- index.html.erb -->

<h1>トップページ</h1>
<p>Find me in app/views/pages/index.html.erb</p>
<% if user_signed_in? %>
  <%= link_to 'ログアウト', destroy_user_session_path, method: :delete %>
<% else %>
  <%= link_to 'サインアップ', new_user_registration_path %>
  <%= link_to 'ログイン', new_user_session_path %>
<% end %>

これで、ログイン状態によってリンクが切替わるようになりました。

f:id:tatehito-st:20191012143845p:plain:w300


f:id:tatehito-st:20191012143859p:plain:w300

5.認証後のリダイレクト先をユーザーページにする

Devise::Controllers::Helpersafter_sign_in_path_forメソッドをオーバーライドすることで、認証後のリダイレクト先をカスタマイズできます。

# application.rb

def after_sign_in_path_for(resource)
    "/user/#{current_user.id}"
  end

※current_userで現在ログインしているユーザー情報を取得できる。

ユーザーページのビューを編集します。ログインユーザーのメールアドレスを表示するようにしてみました。

<!-- show.html.erb -->

<h1>ユーザーページ</h1>
<div>
  あなたのメールアドレス:<%= current_user.email %>
</div>
<div>
  <%= link_to '戻る', root_path %>
</div>

さいごに、ユーザーページのルーティングを編集。

# route.rb

Rails.application.routes.draw do
  root 'pages#index'
  get "user/:id", :to => "pages#show" # この1行を編集
  devise_for :users
end

これで完成😤

ログインするとそのユーザーのページが開きます。

f:id:tatehito-st:20191012151729p:plain:w300

おわりに

ソースコードはこちらです💁‍♂️

github.com

サインインやサインアップページのビューや、動作をカスタマイズするにはrails g devise:views usersrails g devise:controllers usersをしてdevise対応のコントローラーやビューを生成する必要があるようです。今回は最低限の動作確認が目的のため、そこまでは手を出しませんでした。

サンプルアプリをつくるくらいなら簡単ですが、deviseは多機能で、使いこなすのは一筋縄ではいかなそう、という印象を受けました。まあ、それでもゼロから認証機能をつくるよりはよっぽど簡単なのですが。