Docker上のRailsアプリケーションでDevise(認証機能)を使う方法のまとめ。
##参考リンク
- https://github.com/heartcombo/devise
- https://github.com/heartcombo/devise/wiki/How-Tos
- https://github.com/heartcombo/devise/wiki/How-To:-Add-:confirmable-to-Users
##(はじめに)dockerコンテナ内でコマンドを実行する方法 Dockerコンテナの中のアプリケーションでコマンドを実行する場合はまずコンテナに入る。
コンテナの中に入るには**docker
コマンドとdocker-compose
使う方法がある**。
どちらの場合もコンテナは起動している必要がある。
docker exec -it サービス名 シェル
docker-compose exec サービス名 シェル
シェルは基本的にbash
かsh
。アプリケーション毎に異なる。
**▼実例** 例えば、alpine(Linuxディストリビューションの一つ)のrubyを使って作成したdocker上のrailsアプリケーションに入る場合は以下となる。
$ docker exec -it サービス名 sh
/app #
または
$ docker-compose exec サービス名 sh
/app #
/app #
が表示されればコンテナ内に入れている。コンテナから出る時はexit
を入力しEnter。
##ログイン機能の作成方法 ここから本題。railsの`devise`というgemを使ってログイン認証機能を簡単に実装する手順。
##1. deviseのインストール
Gemfileにdeviseを追記し、bundle install
を実行する。
gem 'devise'
railsはdockerの中で起動しているので、docker内のコンテナに入ってからbundle install
を実行する。
$ docker exec -it サービス名 sh
/app # bundle install
以下のように表示されればdeviseパッケージのインストールが完了。
##2. deviseをアプリケーションに導入する
deviseのパッケージインストールが終わったので、次にアプリケーションにdevise機能を実装する。Dockerコンテナに入ったままrails g devise:install
を実行。
/app # rails g devise:install
Running via Spring preloader in process 534
create config/initializers/devise.rb
create config/locales/devise.en.yml
===============================================================================
Depending on your application's configuration some manual setup may be required:
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.
* Required for all applications. *
2. Ensure you have defined root_url to *something* in your config/routes.rb.
For example:
root to: "home#index"
* Not required for API-only Applications *
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>
* Not required for API-only Applications *
4. You can copy Devise views (for customization) to your app by running:
rails g devise:views
* Not required *
===============================================================================
これでdeviseが使えるようになった。
##3. 認証機能が使えるモデルの作成 認証機能が使えるモデルを作成するには、通常の`rails g model モデル名`ではなく`devise`を使う。
・rails g devise モデル名
/app # rails g devise user
Running via Spring preloader in process 572
invoke active_record
create db/migrate/20210414012052_devise_create_users.rb
create app/models/user.rb
invoke test_unit
create test/models/user_test.rb
create test/fixtures/users.yml
insert app/models/user.rb
route devise_for :users
##3-1. migrationファイルの中身 db/migrate/20210414012052_devise_create_users.rb
devise_create_テーブル名 のクラスが生成され、関数の中には各モジュール毎の設定が記述されている。
# frozen_string_literal: true
class DeviseCreateUsers < ActiveRecord::Migration[6.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
カラムの型の記述ルールは以下のようになっている。
t.カラムの型 :カラム名 条件1: 値1, 条件2: 値2,,,
####3-1-1. Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
emailと暗号化したパスワードのカラムを作成している。
null: false
何かしら値がない場合はエラーとなる。
default: ""
初期値は何も指定されていない。
####3-1-2. Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
パスワードリセット用のトークンを保存するカラムと、送信日時を保存するカラム。
####3-1-3. Rememberable
t.datetime :remember_created_at
ログイン状態を維持しておく期間。
####3-1-4. 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
ログインした回数、最新のログイン日時、前回のログイン日時、最新のログインIP、最終のログインIPを保存。
デフォルトはコメントアウト。
####3-1-5. Confirmable
t.string :confirmation_token
t.datetime :confirmed_at
t.datetime :confirmation_sent_at
t.string :unconfirmed_email # Only if using reconfirmable
メールに記載されているURLをクリックして登録完了する時に使うカラム。
確認用の番号(トークン)、登録申請された時間、本登録用のメールを送信した時間、e-mailアドレスを保存する。
デフォルトはコメントアウト。
####3-1-6. 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
一定回数ログインに失敗した時にロックアウトする用のカラム。
ログインの入力可能回数、ロックアウトしたトークン、ロックアウトした時間を保存。
デフォルトはコメントアウト。
####3-1-7. 重複防止のバリデーション(ユニーク設定)
emailやトークンなど重複してはいけないカラムを指定する。
・add_index :テーブル名, :カラム名, unique: true
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
####(補足)追加モジュール デフォルトでは記述がないが、以下のようなモジュールも用意されている。使う場合は追加でカラムの設定が必要。
・timeoutable
一定時間活動していないアカウントのセッションを破棄する。デフォルトは30分が設定されている。
変更したい場合はconfig/initializers/devise.rbに追記する。
・omniauthable
SNS認証機能(twitterやfacebookなど)の追加。intridea/omniauthを使えるようにする。
##3-2. コントローラの中身 コントローラの中で使いたいモジュールを`:モジュール名`で指定する。
app/models/user.rb
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
end
モジュールは複数指定可能。
##3-3. ルーティングの確認 config/routes.rb を確認すると`devise_for: users`が追加されている。
・devise_for: モデル名
指定したモデル名を使ったルーティングを自動設定してくれる。
/users/sign_in
や/users/password/new
といったルートが作成されている。
/app # rails routes
Prefix Verb URI Pattern Controller#Action
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
user_password PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
POST /users/password(.:format) devise/passwords#create
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
user_registration PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
POST /users(.:format) devise/registrations#create
##4. development.rbの設定 config/environments/development.rb に、デフォルトのURLを設定する。
#devise setting
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
##5. デフォルトの認証ページ画面を表示する マイグレーションをしてから、認証ページにアクセスする。
Dockerコンテナ内でrails db:migrate
を実行。
/app # rails db:migrate
== 20210414012052 DeviseCreateUsers: migrating ================================
-- create_table(:users)
-> 0.0302s
-- add_index(:users, :email, {:unique=>true})
-> 0.0041s
-- add_index(:users, :reset_password_token, {:unique=>true})
-> 0.0036s
== 20210414012052 DeviseCreateUsers: migrated (0.0382s) =======================
ブラウザで追加されたルートにアクセスする。
http://localhost:3000/users/sign_in
http://localhost:3000/users/password/new
##6. 日本語に変更(localeの日本語化) デフォルトの言語は英語なので日本語に変更する。(deviseではなくrailsアプリケーションの言語設定を変える)
###6-1. configファイルの変更
config/application.rb に以下を追記。
config.i18n.default_locale = :ja
###6-2. localesディレクトリに言語ファイルを追加 config/locales配下に以下2つのファイルを追加する。
・ja.yml
・devise.ja.yml
(参考)i18nとは?使い方まとめ。ビュー(View),コントローラー(Controller), コンソールでの呼び出し方とlocaleの使い方
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})変更が完了したため、メールを送信しています。
message_unconfirmed: メールアドレスが(%{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} は保存されませんでした。"
https://gist.github.com/yhara/606476
https://github.com/tigrish/devise-i18n/blob/master/rails/locales/ja.yml
###ページをリロード
一部の英語が日本語に変換された。残りはビューを変更する必要がある。
##7. ビューの日本語化 dockerコンテナ内で`rails g devise:views`を実行する。
/app # rails g devise:views
Running via Spring preloader in process 564
invoke Devise::Generators::SharedViewsGenerator
create app/views/devise/shared
create app/views/devise/shared/_error_messages.html.erb
create app/views/devise/shared/_links.html.erb
invoke form_for
create app/views/devise/confirmations
create app/views/devise/confirmations/new.html.erb
create app/views/devise/passwords
create app/views/devise/passwords/edit.html.erb
create app/views/devise/passwords/new.html.erb
create app/views/devise/registrations
create app/views/devise/registrations/edit.html.erb
create app/views/devise/registrations/new.html.erb
create app/views/devise/sessions
create app/views/devise/sessions/new.html.erb
create app/views/devise/unlocks
create app/views/devise/unlocks/new.html.erb
invoke erb
create app/views/devise/mailer
create app/views/devise/mailer/confirmation_instructions.html.erb
create app/views/devise/mailer/email_changed.html.erb
create app/views/devise/mailer/password_change.html.erb
create app/views/devise/mailer/reset_password_instructions.html.erb
create app/views/devise/mailer/unlock_instructions.html.erb
viewsディレクトリ配下にdeviseのディレクトリが追加された。
ディレクトリ | 内容 | ファイル |
---|---|---|
confirmation | パスワード再発行用のフォーム | new.html.erb |
mailer | 送信するメールの内容 | (1)confirmation_instructions.html.erb, (2)email_changed.html.erb, (3)password_change.html.erb, (4)reset_password_instructions.html.erb, (5)unlock_instructions.html.erb |
passwords | パスワードを忘れた時のフォーム | (1)edit.html.erb, (2)new.html.erb |
registrations | ユーザー情報の新規登録と編集フォーム | |
sessions | ログインフォーム | new.html.erb |
shared | 共通のエラーメッセージとリンク部分のテンプレート | |
unlocks | アカウントロック通知メールのフォーム | new.html.erb |
http://localhost:3000/users/sign_in で表示されるビューを編集する。
app/views/devise/sessions/new.html.erb
<h2>ログイン</h2>
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
</div>
<div class="field">
<%= f.label :password %><br />
<%= f.password_field :password, autocomplete: "current-password" %>
</div>
<% if devise_mapping.rememberable? %>
<div class="field">
<%= f.check_box :remember_me %>
<%= f.label :remember_me %>
</div>
<% end %>
<div class="actions">
<%= f.submit "送信" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
下部の`<%= render "devise/shared/links" %>`は以下のファイルを呼び出しているため、該当部分を変更する。
app/views/devise/shared/_links.html.erb
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
<%= link_to "新規登録", new_registration_path(resource_name) %><br />
<% end %>
<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
<%= link_to "パスワードを忘れましたか?", new_password_path(resource_name) %><br />
<% end %>
**▼ページをリロード**
これで日本語化が完了。
##8. フラッシュメッセージの作成 deviseをインストールしたときの指示にしたがってapplication.html.erbにフラッシュメッセージを表示するタグを追加する。
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>
notice
はログインや投稿に成功した時に表示されるメッセージ。
alert
はEメールやPWが正しくない場合に表示されるメッセージ。
app/views/layouts/application.html.erb のbodyタグにフラッシュメッセージを表示するタグを追加。
<body>
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
<%= yield %>
</body>
画面上部にフラッシュメッセージが表示されるようになった。
ただし、この状態ではデフォルト状態で隙間が開いてしまうためフラッシュメッセージが存在する時のみタグを表示するように変更する。
<body>
<% if notice %>
<p><%= notice %></p>
<% end %>
<% if alert %>
<p><%= alert %></p>
<% end %>
<%= yield %>
</body>
![flash2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/c2b2aa47-6127-9240-536d-49a84ae1e0f4.gif)
##9. ログイン後に表示されるページを変更する ログインに成功するとデフォルトでroot_urlにリダイレクトされる。これを任意のページに変更する。
###9-1. rails g controller コントローラ名
例として、pages > show.html.erbを表示する設定にする。
Dockerコンテナの中に入りコントローラーを作成する。
$ docker-compose exec サービス名 sh
/app # rails g controller pages
###9-2. ビューの作成
生成されたapp/views/pages配下に show.html.erb を作成する。
<div>ログイン成功後に表示されるページ</div>
<%= link_to 'ログアウト', destroy_user_session_path, method: :delete %>
###9-3. ルーティングの設定
ルート名をpages_show
とする。
Rails.application.routes.draw do
devise_for :users
root to: 'top#index'
#追記
get '/pages/show', to: 'pages#show', as: :pages_show
end
・get 'URI', to: 'コントローラ名#アクション名, as: :ルート名'
###9-4. コントローラの設定(application_controller.rb) ログインに成功した場合と失敗した場合に表示するビューへのリダイレクトを設定する。
使うルート名はpages_show
とnew_user_session
。詳細はrails routes
で確認できる。
/app # rails routes
Prefix Verb URI Pattern Controller#Action
new_user_session GET /users/sign_in(.:format) devise/sessions#new
pages_show GET /pages/show(.:format) pages#show
new_user_sessionはログインページ。
app/controllers/application_controller.rbに以下のようにメソッドを記述する。
applcation_controller.rbのメソッドは他のコントローラにも読み込まれる(<
で拡張しているため)。
class ApplicationController < ActionController::Base
def after_sign_in_path_for(resource)
pages_show_path
end
private
def sign_in_required
redirect_to new_user_session_url unless user_signed_in?
end
end
####Deviseのログイン後にリンクするページ
after_sign_in_path_for
ヘルパをで指定する。
def after_sign_in_path_for(resource)
パス
end
ルート名_path
は指定したルートのパス('/配下')を表示するヘルパ。
pages_show
を指定した場合、対応するpagesコントローラのshowメソッドが実行される(pages#show
)
####ログインに失敗した場合の処理
ログインに失敗した場合はnew_user_session
private
def sign_in_required
redirect_to new_user_session_url unless user_signed_in?
end
このメソッド名はなんでもいい。pagesコントローラで使う時に合わせる。
private
を記述すると、同じクラス(拡張したクラスも含む)の中からしか読み込めないようにできる。
・unless修飾子を使った条件分岐
trueで実行する処理 unless 条件
user_signed_inが存在すればnew_user_sessionのルートにリダイレクトする。
・redirect_to URL
指定したURLにリダイレクトする
・ルート名_url
指定したルート名のurlを呼び出す。
・unless 条件
ifの逆。条件がfalseだった時に指定した処理を実行する。if !条件
と同じ。
・user_signed_in?
Deviseのヘルパ。ログインしている場合はtureになる。(便利!)
###9-5. コントローラの設定(pages_controller.rb) ログインに成功した時に表示するapp/controllers/pages_controller.rbの設定をする。
before_action
を使って先ほど定義したis_signed_in
メソッドを呼び出してから、showアクションを実行する。
class PagesController < ApplicationController
before_action :is_signed_in, only: [:show]
def show
end
end
・before_action :メソッド名
アクションを指定しない場合は、すべてのアクションの前に指定したメソッドが実行される。
・before_action :メソッド名, only: [:アクション名, アクション名,,,]
only: を使うと指定したアクションを実行する場合のみメソッドを実行する。
・before_action :メソッド名, except: [:アクション名, アクション名,,,]
exceptを使うと指定したアクション以外でメソッドを実行する。
onlyもexceptもアクションが一つの場合は
[ ]
がなくてもいい。
####補足:別の記述方法
deviseのヘルパでauthenticate_user!
を使うとより簡単に記述できる。これは、ログインしてない場合はログインページにリダイレクトするヘルパ。
class PagesController < ApplicationController
before_action :authenticate_user!, only: [:show]
def show
end
end
↓↑ 同じ
class PagesController < ApplicationController
before_action :is_signed_in, only: [:show]
def show
end
end
private
def is_signed_in
redirect_to new_user_session_url unless user_signed_in?
end
###9-6. ブラウザの表示
ログイン画面/users/sign_in
から正しくログインできると指定したページに飛ぶことができる。
##10. Deviseのヘルパ モデル名をuserとして生成した場合(`rails g devise user`)の例。
別のモデル名を使った場合は、userの部分を指定したモデル名に変更する。
###10-1. before_action :authenticate_user!
ログインしてない場合はログインページにリダイレクトするヘルパ。コントローラの上部で使う。
class PagesController < ApplicationController
before_action :authenticate_user!, only: [:show]
def show
end
end
###10-2. user_signed_in?
ユーザーがログインしている場合はtrueを返す。
def show
pp "user_signed_in?:#{user_signed_in?}"
end
###10-3. current_user
現在のセッションのユーザー情報を取得できる。保存してある情報は、4つ。(1)id, (2)email, (3)created_at, (4)updated_at。
irb(main):009:0> User.find[1]
User Load (0.8ms) SELECT "users".* FROM "users"
=> #<User id: 2, email: "111@222", created_at: "2021-04-15 05:08:07.005182000 +0000", updated_at: "2021-04-15 05:08:07.005182000 +0000">
ユーザーのidを呼び出したい場合は、current_user.id
とする。
def show
pp "current_user:#{current_user}"
pp "current_user.id:#{current_user.id}"
end
###10-4. user_session
ユーザーのセッション情報を格納しておく変数。デフォルトは空。
def show
pp "user_session:#{user_session}"
user_session["point"] = 5432
user_session["os"] = ["apple", "windows"]
pp "user_session:#{user_session}"
end
一度ログアウトしてから、再度ログインすると空になる。
##11. 新規登録時のメール承認機能の実装 `confirmable`モジュールを使うとユーザーの新規登録時にメール承認機能をつけることができる。
###11-1. モデルにconfirmable
を追加
app/models/user.rb
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, :confirmable
end
###11-2. メール送信用サーバーの設定
config/environments/development.rb に以下を追記。
Rails.application.configure do
(省略)
# mailer setting
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
:address => 'smtp.gmail.com',
:port => 587,
:user_name => 'gmailのアドレス',
:password => 'gmailのアプリパスワード',
:authentication => :plain,
:enable_starttls_auto => true
}
(省略)
end
###11-3. Deviseのメーラー設定
次に、Deviseのconfigファイルでメーラーを指定する。
config/initializers/devise.rb
config.mailer_sender = 'gmailのアドレス'
###11-4. reconfirmableをfalseにする メールアドレス更新時にメール確認を必須にするreconfirmableをfalseにする。(デフォルトはtrue)
config/initializers/devise.rb
# If true, requires any email changes to be confirmed (exactly the same way as
# initial account confirmation) to be applied. Requires additional unconfirmed_email
# db field (see migrations). Until confirmed, new email is stored in
# unconfirmed_email column, and copied to email column on successful confirmation.
config.reconfirmable = false
###11-5. アプリパスワードの発行 gmailで自動のアプリケーションを使ってメール送信する場合、PWにはアプリパスワードを指定する必要がある。
ログインしてセキュリティを開く。
↓
↓ 「その他」を選択し、名前を適当に入力。
表示されたパスワードをコピーして、:password => 'gmailのアプリパスワード',
にペーストする。
これで、現在のrailsアプリケーションで指定したメールサーバーが使えるようになった。
###11-6. マイグレーションファイルのconfirmableに必要なカラムを有効化する
db/migrate/yyyymmdd_devise_create_users.rb
confirmableのコメントアウトを外す。
## Confirmable
t.string :confirmation_token
t.datetime :confirmed_at
t.datetime :confirmation_sent_at
t.string :unconfirmed_email # Only if using reconfirmable
アプリケーションをctrl + c
で終了してから再起動し、rails db:migrate
を実行する。
#アプリケーションの起動(プロジェクトのルートディレクトリで)
$ docker-compsoe up
#コンテナ内に入る
$ docker exec -it コンテナ名 sh
#マイグレーション
$ rails db:migrate
###11-7. ブラウザで検証 新規登録時のメール確認なので、`/users/sign_up`にアクセスする。
「Sign up」をクリックするとTOPページにリダイレクトし、上部に「
本人確認用のメールを送信しました。メール内のリンクからアカウントを有効化させてください。」が表示される。
Welcome example@com!
You can confirm your account email through the link below:
Confirm my account
ログイン画面に飛び、「リンクをクリックするとメールアドレスが確認できました」が表示される。
登録したEメールとパスワードを入力すればログインが完了する。
localhostのポート番号が異なる場合はconfig/environments/development.rbで設定。
####link_toで生成されるリンク
<%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>
confirmation_urlヘルパに@resource
と@token
の2つの変数を渡している。
##11-8. confirmableの送信メールの内容を変更する 初回登録時に送信されるメール内容は以下ファイルに記述されている。 app/views/devise/mailer/confirmation_instructions.html.erb
<p>Welcome <%= @email %>!</p>
<p>You can confirm your account email through the link below:</p>
<p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></p>
↓
<p>ご登録ありがとうございます。</p>
<p>登録されたメールアドレスは<%= @email %>です。</p>
<p>下記リンクをクリックして最終承認を完了させてください。</p>
<p><%= link_to '「ご登録の承認」', confirmation_url(@resource, confirmation_token: @token) %></p>