ユーザー認証機能 (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
というパスにアクセスすることで、ユーザーの新規登録画面を開くことができたりします。
マイグレーション実行
前項でマイグレーションファイルが自動的に生成されましたので、マイグレーションを実行しておきます。
$ 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 で使うのは新規登録&ログインのみですが、それを含めどのようなルーティングが使えるのかは確認しておいてください。