Chapter 11

3-1. ユーザー認証機能作成 (Devise)

Masuyama
Masuyama
2022.10.15に更新

ユーザー認証機能 (Devise)

今回から、近年の Web アプリケーションではほぼ備わっているユーザー認証機能を作成します。
TechLog では誰でも学習ログを投稿できるわけではなく、事前に新規登録したユーザーだけが投稿できるようにしていきます。

devise とは

ここでは便利なログイン機能を手軽に実装できる devise という gem を使用します。

もちろん、ユーザー認証機能をゼロから作成しても良いのですが、基本的な新規登録・ログイン・ログアウト機能ですら穴なく作ることは難しいものです。

そこで devise を使うと、簡単に新規登録・ログイン・ログアウトといった基礎的な機能を実装できるのはもちろん、
ログインしているユーザー ID を簡単に view で使えるなど、ユーザー認証機能に付随して使いたい機能が多く備わっています。

他にもパスワード再発行機能など、使える機能は多いのですが TechLog では基本的な機能の実装のみに留めておきます。

devise をインストール

Gemfile を開き、以下の 1 行を追加します。
(devise は本番環境でも使用するため、group は development でも test でも無いところに記載してください。)

Gemfile

gem 'devise' # 追記

Gemfile に追記が完了したら、いつも通り bundle install を実行します。

$ bundle install
Fetching devise 4.8.1
Installing devise 4.8.1
Bundle complete! 24 Gemfile dependencies, 102 gems now installed.
Bundled gems are installed into `./.bundle`

初期設定

devise の初期設定に必要なファイルは、コマンドで作成できます。
devise をインストールすると rails g devise:xxx というコマンドがいくつか使えるようになるのですが、
その中の一つで rails g devise:install コマンドを最初は使います。

$ bundle exec rails g devise:install
      create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================

Depending on your application's configuration some manual setup may be required:

コマンドを実行することで、config ディレクトリ配下にファイルが生成されました。

  • config/initializers/devise.rb
  • config/locales/devise.en.yml

一つ目の devise.rb は、devise に関する様々な設定を記述するファイルとだけ今はご認識ください。

もう一つの devise.en.yml は、devise を使った操作で画面にメッセージを表示する際、どのような内容を表示するかを決めているファイルです。
ファイル名の .en は英語 (English) であることを示しており、その名の通り英語でのメッセージ専用のファイルとなっています。
しかし TechLog は日本語の Web アプリですので、後のカリキュラムで日本語用のファイルも作成していきます。

User モデル作成

次に、ユーザーを表す User モデルを作成します。

通常、モデルを作成するには rails g model Xxx コマンドですが、
devise を活用した User モデルを作成するには rails g devise User とする必要があるのでご注意ください。

$ bundle exec rails g devise User
      invoke  active_record
      create    db/migrate/20220716053859_devise_create_users.rb
      create    app/models/user.rb
      invoke    rspec
      create      spec/models/user_spec.rb
      invoke      factory_bot
      create        spec/factories/users.rb
      insert    app/models/user.rb
       route  devise_for :users

新しく生成されたファイルと、自動的に編集されたファイルについて軽くおさらいしておきましょう。

  • db/migrate/20220716053859_devise_create_users.rb
    • users テーブルを作成するためのマイグレーションファイル
  • app/models/user.rb
    • User モデルを扱うためのファイル
  • spec/models/user_spec.rb
    • User モデルの RSpec (テスト) ファイル
  • spec/factories/users.rb
    • テスト内で一時的に User を作成するための FactoryBot 用ファイル

また、ルーティングも自動的に作られていることに注意してください。

config/routes.rb

Rails.application.routes.draw do
  devise_for :users # この1行が追加されている
  root 'home#top'
end

見慣れない形ではありますが devise ではこの 1 行で基本的なルーティング設定は完結するよう、
裏側で複雑な設定が行われています。

例えば /users/sign_up というパスにアクセスすることで、ユーザーの新規登録画面を開くことができたりします。

https://qiita.com/beanzou/items/1ff9c7cba61fd1fa5c80

マイグレーション実行

前項でマイグレーションファイルが自動的に生成されましたので、マイグレーションを実行しておきます。

$ bundle exec rails db:migrate
== 20220716053859 DeviseCreateUsers: migrating ================================
-- create_table(:users)
   -> 0.0009s
-- add_index(:users, :email, {:unique=>true})
   -> 0.0003s
-- add_index(:users, :reset_password_token, {:unique=>true})
   -> 0.0003s
== 20220716053859 DeviseCreateUsers: migrated (0.0015s) =======================

test 環境についても同じくマイグレーションしておきます。

$ RAILS_ENV=test bundle exec rails db:migrate
...

nickname カラムを追加

TechLog では、誰が投稿した学習ログであるかを表すために ニックネーム (nickname) を使用します。
しかし、現在の users テーブルでは nickname カラムを追加していないため、追加するためのマイグレーションファイルを生成します。

$ bundle exec rails g migration AddNicknameToUser nickname:string
      invoke  active_record
      create    db/migrate/20220716061809_add_nickname_to_user.rb

生成されたマイグレーションファイルを開き、以下のように修正します。

db/migrate/2022xxxxxxxx_add_nickname_to_user.rb

class AddNicknameToUser < ActiveRecord::Migration[7.0]
  def change
    add_column :users, :nickname, :string
  end
end

では development と test それぞれの環境のデータベースでマイグレーションを実行しておきます。

development

$ bundle exec rails db:migrate
== 20220716061809 AddNicknameToUser: migrating ====================================
-- add_column(:users, :nickname, :string)
   -> 0.0009s
== 20220716061809 AddNicknameToUser: migrated (0.0009s) ===========================

test

$ RAILS_ENV=test bundle exec rails db:migrate
== 20220716061809 AddNicknameToUser: migrating ====================================
-- add_column(:users, :nickname, :string)
   -> 0.0005s
== 20220716061809 AddNicknameToUser: migrated (0.0005s) ===========================

さて、実は devise では新規登録やログイン時に受け付けるパラメータを制限する仕組みが備わっています。

そのため、マイグレーションで nickname カラムを増やしていたとしても
新規登録時の入力フォームで渡されたパラメータ内の nickname は弾かれてしまいます。

そのため、ApplicationController にてストロングパラメータを設定しましょう。

公式の READMEの通りに今回は設定します。

app/controllers/application_controller.rb を以下のように書き換えてください。

app/controllers/application_controller.rb

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

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:nickname])
  end
end

devise_parameter_sanitizer.permit(:sign_up, keys: [:nickname])という 1 行では、
sign_up、つまり新規登録時に nickname というキーのパラメータも許可することを設定しています。

変更をコミット

これで devise を使うための初期設定は完了しました。
ここまでの変更をコミットしておきましょう。

$ git add .
$ git commit -m "deviseインストールと初期設定完了"
$ git push

宿題

devise で出来ること

devise を使うと最低限の設定でユーザー認証機能を実装できる反面、
devise (gem) の中で何をやっているかが分からないため、ちょっとしたカスタマイズをしたい時に取っ付きにくいというデメリットがあります。

しかし、よく使われる便利な devise の便利な機能は限られているため、その全容を把握しておくだけでも今後の実装がだいぶ楽になります。

以下の記事を参考に、どのようなヘルパーメソッドがあるか?認証周りの裏側ではどのような処理がされているのか?を一度読んでおくといいでしょう。

devise のルーティング

今回のカリキュラムでは config/routes.rb に 1 行が自動で追加されていましたね。

  devise_for :users

この 1 行により users/sign_up というパスで新規登録画面を表示できたりと、内部的に様々なルーティングを実現できました。

TechLog で使うのは新規登録&ログインのみですが、それを含めどのようなルーティングが使えるのかは確認しておいてください。