こんにちは!あっきー(@IwswAkht)です!
Ruby on Railsの Gemである「Devise」を使った認証機能の実装方法を書きました。
すでに多くの記事もあるし、関わった開発案件でも多々使われている場面はあったのですが、実際に自分でやったことがなかったので忘備録も兼ねた記事になります。
Web系の開発をさせていただくようになってまだ経験は浅いなりに思ったことなのですが、開発現場では言語の知識をめちゃくちゃ覚えておくというよりは以下のことが結構だいじだなと感じています。
・ライブラリを知っていて使えるか
・DBの設計の知識を持っているか
・ある程度のインフラ知識があるか
なので、今後はライブラリなどを積極的に使って見て、その方法や使い勝手などを記事にまとめておきたいと思い本記事を執筆しました。
今後とも継続して知識を蓄積していき、自分や他の誰かの役に立つ記事を増やしていければと。
Railsプロジェクトの作成
適当な作業フォルダを作成してから Rails tutorialに沿った方法で作成します。
順番に実行していってください。
# 1.作業フォルダ作成
$ mkdir dev_rails
# 2.作業フォルダに移動
$ cd dev_rails
# 3.ドキュメントをインストールしない設定
$ printf "install: --no-document \nupdate: --no-document\n" >> ~/.gemrc
# 4.プロジェクト(sample_app)の作成
$ rails _5.1.6_ new sample_app
# 5.プロジェクトフォルダに移動
$ cd sample_app
※rbenvでバージョン管理をした上で作業した方がいいです。以下のURL内の「rbenv で Ruby のインストール」でやり方を書いています。
https://iwasawa-officialweb.com/2019/11/06/rails_secure_shell_app/
動作確認
次に簡単に動作確認をしておきましょう。
viewファイルは slimで書きたいので gemを追加した上でインストールします。
gem 'slim-rails'
以下のコマンドを順番に実行してください。
# 1.bundle install
$ bundle install --path vendor/bundle
# 2.コントローラとindexファイルの作成
$ rails g controller homes index
必要なファイルを作成しましたらルートの設定を行います。
Rails.application.routes.draw do
root 'homes#index'
end
rails s
でサーバーを起動し、http://localhost:3000/
にアクセスして以下の画面が表示されればOKです!
動作の確認が取れましたらいよいよ Deviseを実装してきます。 ## Deviseの導入
今回はDeviseでログイン/ログアウト/登録
の機能を実装していきます。
まず最初に gemで slimをインストールした手順と同様に Deviseの Gemも追加します。
gem 'devise'
以下のコマンドを作成します。
$ bundle install --path vendor/bundle
これで Deviseを使うための準備が完了しました。
以下の手順に沿って実装していきます。
1. プロジェクトに Deviseを適用させる
以下コマンドを実行してください。
これにより Deviseの設定ファイルが作成されます。
$ rails g devise:install
Running via Spring preloader in process 51076
create config/initializers/devise.rb
create config/locales/devise.en.yml
===============================================================================
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:
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
4. You can copy Devise views (for customization) to your app by running:
rails g devise:views
===============================================================================
2. Modelの作成
Deviseに対応する(ログイン機能用)モデルを作成します。
モデル名はUser
という前提で進めていきます。
以下のコマンドを実行してください。
$ rails g devise user
対応するマイグレーションファイルが以下のように生成されます。
用途に応じてコメントアウトを外します。(今回はデフォルトのままで大丈夫です)
マイグレーションファイルを確認しましたら$ rails db:migrate
コマンドを実行してマイグレーションします。
# frozen_string_literal: true
class DeviseCreateUsers < ActiveRecord::Migration[5.1]
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
また、Userモデルのファイルも作成されていますので確認しておきましょう。
Deviseでは初期でバリデーションがかけられていますが変更したい場合などはこちらのファイルを編集します。
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
end
Controllerの作成
Model(User)に対応するコントローラーを作成します。
以下のコマンドを実行してください。
$ rails g devise user
Running via Spring preloader in process 51755
create app/controllers/users/confirmations_controller.rb
create app/controllers/users/passwords_controller.rb
create app/controllers/users/registrations_controller.rb
create app/controllers/users/sessions_controller.rb
create app/controllers/users/unlocks_controller.rb
create app/controllers/users/omniauth_callbacks_controller.rb
===============================================================================
Some setup you must do manually if you haven't yet:
Ensure you have overridden routes for generated controllers in your routes.rb.
For example:
Rails.application.routes.draw do
devise_for :users, controllers: {
sessions: 'users/sessions'
}
end
===============================================================================
色々ファイルが作成されてますね。
ファイル名から直感的にわかるかと思うのですが、登録処理やログイン/ログアウトに関するコントローラーが作成されまして各々編集しながら各機能に対する処理を記述します。(今回はデフォルトのままで大丈夫です)
また、ログにも出てますが、まだ設定が完了していません。コントローラーに対応するビューの設定をルーティングしていく必要があるみたいですね。
Routesの設定
今回はログイン/ログアウト/登録
なので以下のようにルートファイルを編集します
Rails.application.routes.draw do
devise_for :users, controllers: {
sessions: 'users/sessions',
registrations: 'users/registrations',
}
root 'homes#index'
end
Viewの作成
残りはビューファイルの作成です。
Deviseの以下のコマンドで必要なファイルを一括で作成できます。
$ rails g devise:views users
Running via Spring preloader in process 51718
invoke Devise::Generators::SharedViewsGenerator
create app/views/users/shared
create app/views/users/shared/_error_messages.html.erb
create app/views/users/shared/_links.html.erb
invoke form_for
create app/views/users/confirmations
create app/views/users/confirmations/new.html.erb
create app/views/users/passwords
create app/views/users/passwords/edit.html.erb
create app/views/users/passwords/new.html.erb
create app/views/users/registrations
create app/views/users/registrations/edit.html.erb
create app/views/users/registrations/new.html.erb
create app/views/users/sessions
create app/views/users/sessions/new.html.erb
create app/views/users/unlocks
create app/views/users/unlocks/new.html.erb
invoke erb
create app/views/users/mailer
create app/views/users/mailer/confirmation_instructions.html.erb
create app/views/users/mailer/email_changed.html.erb
create app/views/users/mailer/password_change.html.erb
create app/views/users/mailer/reset_password_instructions.html.erb
create app/views/users/mailer/unlock_instructions.html.erb
user@usernoMacBook-Air sample_app % rails g devise:controllers users
最初に動作確認で作ったファイルをログイン後の画面として以下の編集を加えてください。
h1 ログイン後の画面
= link_to 'ログアウト', destroy_user_session_path, method: :delete
ここまで出来ましたらrails s
でサーバーを起動しまして各画面を確認してみましょう。
http://localhost:3000/users/sign_up
`http://localhost:3000/users/sign_in` ![devise-in202004281037.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257800/83f4a1f0-6b4b-95ce-1461-252eafeb0a58.png) `http://localhost:3000/`
![devise-top202004281036.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257800/f8bea654-440c-3ba6-11cb-a781dd875467.png)
適当に`http://localhost:3000/users/sign_up`からテストユーザーを作ってみてください。
認証制御
現在の状況ですとhttp://localhost:3000/
のURLを直接叩くと認証(ログイン)をしていないのにアクセスすることが可能です。
これはアプリ的に非常によろしくないですね。
なのでログイン後にしかアクセスすることが出来ないよう制御をかけましょう。
Deviseを使った場合は認証後にアクセスしたいビューに対応するコントローラに以下の編集を加えることで完了します。
class HomesController < ApplicationController
before_action :authenticate_user! # 追加
def index
end
end
これでログイン前にログイン後の画面にアクセスするとログイン画面にリダイレクトされ、逆にログイン中にログイン画面へアクセスするとトップ画面にリダイレクトさせるようになります。
ほとんどコマンドで、あとは数行の追加で認証機能が実装できてめちゃくちゃ便利ですよね。
日本語対応
デフォルトでは英語対応なので日本語対応に変更しましょう。
以下のファイルに変更を加えてください。
require_relative 'boot'
require 'rails/all'
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module SampleApp
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 5.1
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
config.i18n.default_locale = :ja #追加(言語対応)
end
end
続いてconfig/locales/
配下にdevise.ja.yml
とja.yml
を作成しそれぞれに編集を加えます。
ja:
errors:
messages:
not_found: "は見つかりませんでした"
# not_found: "not found"
already_confirmed: "は既に登録済みです"
# already_confirmed: "was already confirmed"
not_locked: "は凍結されていません"
# not_locked: "was not locked"
devise:
failure:
unauthenticated: 'ログインしてください。'
# unauthenticated: 'You need to sign in or sign up before continuing.'
unconfirmed: '本登録を行ってください。'
# unconfirmed: 'You have to confirm your account before continuing.'
locked: 'あなたのアカウントは凍結されています。'
# locked: 'Your account is locked.'
invalid: 'メールアドレスかパスワードが違います。'
# invalid: 'Invalid email or password.'
invalid_token: '認証キーが不正です。'
# invalid_token: 'Invalid authentication token.'
timeout: 'セッションがタイムアウトしました。もう一度ログインしてください。'
# timeout: 'Your session expired, please sign in again to continue.'
inactive: 'アカウントがアクティベートされていません。'
# inactive: 'Your account was not activated yet.'
sessions:
signed_in: 'ログインしました。'
# signed_in: 'Signed in successfully.'
signed_out: 'ログアウトしました。'
# signed_out: 'Signed out successfully.'
passwords:
send_instructions: 'パスワードのリセット方法を数分以内にメールでご連絡します。'
# send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.'
updated: 'パスワードを変更しました。'
# updated: 'Your password was changed successfully. You are now signed in.'
confirmations:
send_instructions: '登録方法を数分以内にメールでご連絡します。'
# send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.'
confirmed: 'アカウントを登録しました。'
# confirmed: 'Your account was successfully confirmed. You are now signed in.'
registrations:
signed_up: 'アカウント登録を受け付けました。確認のメールをお送りします。'
# signed_up: 'You have signed up successfully. If enabled, a confirmation was sent to your e-mail.'
updated: 'アカウントを更新しました。'
# updated: 'You updated your account successfully.'
destroyed: 'アカウントを削除しました。またのご利用をお待ちしております。'
# destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.'
unlocks:
send_instructions: 'アカウントの凍結解除方法を数分以内にメールでご連絡します。'
# send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.'
unlocked: 'アカウントを凍結解除しました。'
# unlocked: 'Your account was successfully unlocked. You are now signed in.'
mailer:
confirmation_instructions:
subject: 'アカウントの登録方法'
# subject: 'Confirmation instructions'
reset_password_instructions:
subject: 'パスワードの再設定'
# subject: 'Reset password instructions'
unlock_instructions:
subject: 'アカウントの凍結解除'
# subject: 'Unlock Instructions'
ja:
activerecord:
attributes:
user:
confirmation_sent_at: パスワード確認送信時刻
confirmation_token: パスワード確認用トークン
confirmed_at: パスワード確認時刻
created_at: 作成日
current_password: 現在のパスワード
current_sign_in_at: 現在のログイン時刻
current_sign_in_ip: 現在のログインIPアドレス
email: Eメール
encrypted_password: 暗号化パスワード
failed_attempts: 失敗したログイン試行回数
last_sign_in_at: 最終ログイン時刻
last_sign_in_ip: 最終ログインIPアドレス
locked_at: ロック時刻
password: パスワード
password_confirmation: パスワード(確認用)
remember_created_at: ログイン記憶時刻
remember_me: ログインを記憶する
reset_password_sent_at: パスワードリセット送信時刻
reset_password_token: パスワードリセット用トークン
sign_in_count: ログイン回数
unconfirmed_email: 未確認Eメール
unlock_token: ロック解除用トークン
updated_at: 更新日
models:
user: ユーザ
devise:
confirmations:
confirmed: メールアドレスが確認できました。
new:
resend_confirmation_instructions: アカウント確認メール再送
send_instructions: アカウントの有効化について数分以内にメールでご連絡します。
send_paranoid_instructions: メールアドレスが登録済みの場合、本人確認用のメールが数分以内に送信されます。
failure:
already_authenticated: すでにログインしています。
inactive: アカウントが有効化されていません。メールに記載された手順にしたがって、アカウントを有効化してください。
invalid: "%{authentication_keys}またはパスワードが違います。"
last_attempt: もう一回誤るとアカウントがロックされます。
locked: アカウントは凍結されています。
not_found_in_database: "%{authentication_keys}またはパスワードが違います。"
timeout: セッションがタイムアウトしました。もう一度ログインしてください。
unauthenticated: アカウント登録もしくはログインしてください。
unconfirmed: メールアドレスの本人確認が必要です。
mailer:
confirmation_instructions:
action: メールアドレスの確認
greeting: "%{recipient}様"
instruction: 以下のリンクをクリックし、メールアドレスの確認手続を完了させてください。
subject: メールアドレス確認メール
email_changed:
greeting: こんにちは、%{recipient}様。
message: あなたのメール変更(%{email})のお知らせいたします。
subject: メール変更完了。
password_change:
greeting: "%{recipient}様"
message: パスワードが再設定されたことを通知します。
subject: パスワードの変更について
reset_password_instructions:
action: パスワード変更
greeting: "%{recipient}様"
instruction: パスワード再設定の依頼を受けたため、メールを送信しています。下のリンクからパスワードの再設定ができます。
instruction_2: パスワード再設定の依頼をしていない場合、このメールを無視してください。
instruction_3: パスワードの再設定は、上のリンクから新しいパスワードを登録するまで完了しません。
subject: パスワードの再設定について
unlock_instructions:
action: アカウントのロック解除
greeting: "%{recipient}様"
instruction: アカウントのロックを解除するには下のリンクをクリックしてください。
message: ログイン失敗が繰り返されたため、アカウントはロックされています。
subject: アカウントの凍結解除について
omniauth_callbacks:
failure: "%{kind} アカウントによる認証に失敗しました。理由:(%{reason})"
success: "%{kind} アカウントによる認証に成功しました。"
passwords:
edit:
change_my_password: パスワードを変更する
change_your_password: パスワードを変更
confirm_new_password: 確認用新しいパスワード
new_password: 新しいパスワード
new:
forgot_your_password: パスワードを忘れましたか?
send_me_reset_password_instructions: パスワードの再設定方法を送信する
no_token: このページにはアクセスできません。パスワード再設定メールのリンクからアクセスされた場合には、URL をご確認ください。
send_instructions: パスワードの再設定について数分以内にメールでご連絡いたします。
send_paranoid_instructions: メールアドレスが登録済みの場合、パスワード再設定用のメールが数分以内に送信されます。
updated: パスワードが正しく変更されました。
updated_not_active: パスワードが正しく変更されました。
registrations:
destroyed: アカウントを削除しました。またのご利用をお待ちしております。
edit:
are_you_sure: 本当によろしいですか?
cancel_my_account: アカウント削除
currently_waiting_confirmation_for_email: "%{email} の確認待ち"
leave_blank_if_you_don_t_want_to_change_it: 空欄のままなら変更しません
title: "%{resource}編集"
unhappy: 気に入りません
update: 更新
we_need_your_current_password_to_confirm_your_changes: 変更を反映するには現在のパスワードを入力してください
new:
sign_up: アカウント登録
signed_up: アカウント登録が完了しました。
signed_up_but_inactive: ログインするためには、アカウントを有効化してください。
signed_up_but_locked: アカウントが凍結されているためログインできません。
signed_up_but_unconfirmed: 本人確認用のメールを送信しました。メール内のリンクからアカウントを有効化させてください。
update_needs_confirmation: アカウント情報を変更しました。変更されたメールアドレスの本人確認のため、本人確認用メールより確認処理をおこなってください。
updated: アカウント情報を変更しました。
updated_but_not_signed_in: あなたのアカウントは正常に更新されましたが、パスワードが変更されたため、再度ログインしてください。
sessions:
already_signed_out: 既にログアウト済みです。
new:
sign_in: ログイン
signed_in: ログインしました。
signed_out: ログアウトしました。
shared:
links:
back: 戻る
didn_t_receive_confirmation_instructions: アカウント確認のメールを受け取っていませんか?
didn_t_receive_unlock_instructions: アカウントの凍結解除方法のメールを受け取っていませんか?
forgot_your_password: パスワードを忘れましたか?
sign_in: ログイン
sign_in_with_provider: "%{provider}でログイン"
sign_up: アカウント登録
minimum_password_length: "(%{count}字以上)"
unlocks:
new:
resend_unlock_instructions: アカウントの凍結解除方法を再送する
send_instructions: アカウントの凍結解除方法を数分以内にメールでご連絡します。
send_paranoid_instructions: アカウントが見つかった場合、アカウントの凍結解除方法を数分以内にメールでご連絡します。
unlocked: アカウントを凍結解除しました。
errors:
messages:
already_confirmed: は既に登録済みです。ログインしてください。
confirmation_period_expired: の期限が切れました。%{period} までに確認する必要があります。 新しくリクエストしてください。
expired: の有効期限が切れました。新しくリクエストしてください。
not_found: は見つかりませんでした。
not_locked: は凍結されていません。
not_saved:
one: エラーが発生したため %{resource} は保存されませんでした。
other: "%{count} 件のエラーが発生したため %{resource} は保存されませんでした。"
以上です。
さいごに
最後まで読んでいただきありがとうございます。
今回は基本的な Deviseの扱い方のみになりますが、次は SNSログインとの連携や devise_invitableでの連携などもやってみようかと思います。
自分のブログでも本記事の内容は投稿していますが、ブログでは技術系以外のことも更新していますので興味があればみていってください。
https://iwasawa-officialweb.com/