gem devise の Getting started 翻訳
Google Chrome の 翻訳機能って便利ですよね。
私もあれがなかったら普段いろんなリファレンスとか読むのがもっと大変だったと思います。
ただ、コードブロックなども翻訳してしまうので
GitHub の README.md などはうまく翻訳されなくて
本文と訳文をいったりきたりしてなかなかに面倒です。
今回、Rails プロジェクトに devise
を導入するにあたり
Getting started の手順をなかなか汲み取れなかったので良い感じに翻訳してみました。
主に DeepL の翻訳+筆者の意訳でまとめてます。
原文みながら翻訳みたい方は以下を Chrome で 日本語に翻訳 したりしながらみた方が早いです。
原文
heartcombo / devise | GitHub
Getting started
Devise 4.0はRails 4.1以降で動作します。Gemfileに以下の行を追加します。
gem 'devise'
その後、 bundle install
を実行します。
次にジェネレーターを実行します。
$ rails generate devise:install
この時点で、コンソールにいくつかの指示が表示されます。
これらの指示の中で、各環境での Devise メーラーのデフォルト URL オプションを設定する必要があります。
以下は、config/environments/development.rb
で設定可能なものです。
config.action_mailer.default_url_options = { host: 'localhost', port. 3000 }
ジェネレーターは、Deviseの設定オプションのすべてを説明するイニシャライザをインストールします。
これを見ておくことは必須です。
これが完了したら、ジェネレータを使用してモデルにDeviseを追加する準備ができています。
次のコマンドでは、MODELをアプリケーションのユーザに使用されるクラス名に置き換えます(よくあるのはUserですが、Adminにすることもできます)。これはモデルを作成し(モデルが存在しない場合)、デフォルトのDeviseモジュールで設定します。
ジェネレータはまた、config/routes.rb
ファイルがDeviseコントローラを指すようにconfig/routes.rb
ファイルを設定します。
$ rails generate devise MODEL
次に、確認可能やロック可能など、追加したい追加の設定オプションがないかMODELをチェックします。
オプションを追加する場合は、必ず移行ファイル(ORMがサポートしている場合はジェネレーターが作成したもの)を検査し、適切なセクションのコメントを解除してください。例えば、モデルにconfirmableオプションを追加した場合、マイグレーションのConfirmableセクションのコメントを外す必要があります。
次に、以下を実行します。
rails db:migrate
Deviseの設定オプションを変更した後、アプリケーションを再起動する必要があります(これにはspringの停止も含まれます)。そうしないと、ユーザーがログインできなかったり、ルートヘルパーが未定義だったりといった奇妙なエラーが発生します。
Controller filters and helpers
Devise は、コントローラやビューの内部で使用するためのヘルパーを作成します。ユーザー認証機能を持つコントローラを設定するには、次の before_action を追加します
(devise モデルが 'User'
であると仮定します)。
before_action :authenticate_user!
Rails 5では、protect_from_forgery
がbefore_action
チェーンの前に付加されなくなったため、protect_from_forgery
の前にauthenticate_user
を設定していると、
リクエストの結果が "Can't verify CSRF token authenticity"
になってしまうことに注意してください。これを解決するには、これらを呼び出す順番を変更するか、
protect_from_forgery prepend: true
を使用します。
デバイスのモデルが User
以外の場合は、"_user
" を "_yourmodel"
に置き換えてください。
以下の説明にも同じロジックが適用されます。
ユーザーがサインインしているかどうかを確認するには、以下のヘルパーを使用します。
user_signed_in?
現在サインインしているユーザーに対しては、このヘルパーを使用できます。
current_user
このスコープのセッションにアクセスすることができます。
user_session
ユーザーにサインインした後、アカウントを確認した後、またはパスワードを更新した後、Devise はリダイレクト先のスコープされたルート・パスを探します。例えば、:user
リソースを使用している場合、user_root_path
が存在すれば使用され、そうでなければデフォルトの root_path
が使用されます。これは、routes:
の中にルートを設定する必要があることを意味します。
root to: 'home#index'
after_sign_in_path_for
と after_sign_out_path_for
をオーバーライドしてリダイレクトフックをカスタマイズすることもできます。
例えば Devise モデルが User
ではなく Member
と呼ばれている場合、利用可能なヘルパーは以下のようになります。
before_action :authenticate_member!
member_signed_in?
current_member
member_session
Configuring Models
モデルの Devise メソッドでは、モジュールを設定するためのオプションも用意されています。
たとえば、以下のようにハッシュアルゴリズムのcostを選ぶことができます。
devise :database_authenticatable, :registerable, :confirmable, :recoverable, stretches: 13
:stretches
以外にも、他のオプションとして、:pepper
, :encryptor
, :confirm_within
, :remember_for
, :timeout_in
, :unlock_in
を定義することができます。
詳細については、上で説明した devise:install
ジェネレータを起動したときに作成されたイニシャライザファイルを参照してください。このファイルは通常 /config/initializers/devise.rb
にあります。
Strong Parameters
以前のバージョンのDeviseについては、以下を参照してください。
独自のビューをカスタマイズすると、フォームに新しい属性を追加してしまうことがあります。Rails 4 では、パラメータのサニタイズをモデルからコントローラに移したため、Deviseでもこの問題をコントローラで処理するようになりました。
Deviseには、任意のパラメータセットをモデルに渡すことを許可するアクションが3つあるだけで、サニタイズが必要になります。これらのアクションの名前とデフォルトで許可されているパラメータは以下の通りです。
-
sign_in
(Devise::SessionsController#create
)- 認証キーのみを許可する (like
email
)
- 認証キーのみを許可する (like
-
sign_up
(Devise::RegistrationsController#create
)- 認証キーと
password
,password_confirmation
を許可する
- 認証キーと
-
account_update
(Devise::RegistrationsController#update
)- 認証キーと
password
,password_confirmation
,current_password
を許可する
- 認証キーと
追加のパラメータを許可したい場合 (レイジーウェイ™) は、ApplicationController
のシンプルな before
アクションで許可することができます。
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:username])
end
end
上記は、パラメータが単純なスカラ型である追加のフィールドに対しても動作します。ネストされた属性を持っている場合 (例えば accepts_nested_attributes_for
を使用しているとします)、それらのネストと型について devise に伝える必要があります。
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :last_name, address_attributes: [:country, :state, :city, :area, :postal_code]])
end
end
Devise では、ブロックを渡すことで Devise のデフォルトを完全に変更したり、カスタム動作を呼び出すことができます。
ユーザー名と電子メールに単純なスカラ値を許可するには、以下のようにします。
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_in) do |user_params|
user_params.permit(:username, :email)
end
end
ユーザーが登録時に取ることができる役割を表現するチェックボックスがいくつかある場合、ブラウザはそれらの選択されたチェックボックスを配列として送信します。配列はStrong Parametersが許可しているスカラ値の1つではないので、以下のようにDeviseを設定する必要があります。
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up) do |user_params|
user_params.permit({ roles: [] }, :email, :password, :password_confirmation)
end
end
許可されるスカラのリストと、ネストされたハッシュや配列で許可されるキーの宣言方法については以下を参照してください。
複数の Devise モデルを使用している場合、モデルごとに異なるパラメータサニタイザを設定したい場合があります。この場合は、Devise::ParameterSanitizer
を継承し、独自のロジックを追加することをお勧めします。
class User::ParameterSanitizer < Devise::ParameterSanitizer
def initialize(*)
super
permit(:sign_up, keys: [:username, :email])
end
end
そして、それを使用するようにコントローラを設定します。
class ApplicationController < ActionController::Base
protected
def devise_parameter_sanitizer
if resource_class == User
User::ParameterSanitizer.new(User, :user, params)
else
super # Use the default one
end
end
end
上の例では、ユーザが :username
と :email
の両方を指定することができます。パラメータを設定する方法としては、カスタムコントローラで上記の before
フィルタを定義する方法があります。コントローラの設定方法やカスタマイズ方法については、以下のいくつかのセクションで詳しく説明します。
Configuring views
私たちは、認証を利用したアプリケーションを素早く開発できるように Devise を構築しました。しかし、カスタマイズが必要なときに邪魔になることはありません。
Deviseはエンジンなので、すべてのビューはgemの中にパッケージ化されています。これらのビューは使い始めるのに役立ちますが、しばらくすると変更したくなるかもしれません。そのような場合は、以下のジェネレータを呼び出すだけで、すべてのビューをアプリケーションにコピーしてくれます。
rails generate devise:views
アプリケーションに複数の Devise モデル (User
や Admin
など) がある場合、Devise はすべてのモデルに同じビューを使用していることに気づくでしょう。幸いなことに、Devise はビューを簡単にカスタマイズする方法を提供しています。config/initializers/devise.rb
ファイルの中で config.scoped_views = true
を設定するだけです。
そうすると、users/sessions/new
や admins/sessions/new
のように役割に応じたビューを持つことができるようになります。スコープ内にビューが見つからない場合、Deviseはdevise/sessions/new
のデフォルトビューを使用します。ジェネレーターを使ってスコープ付きのビューを生成することもできます。
rails generate devise:views users
registerableモジュールやconfirmableモジュールのように、いくつかのビューのセットだけを生成したい場合は、モジュールのリストを-v
フラグでジェネレータに渡すことができます。
rails generate devise:views -v registrations confirmations
Configuring controllers
ビューレベルでのカスタマイズが不十分な場合は、以下の手順で各コントローラをカスタマイズすることができます。
1. スコープを必要とするジェネレータを使用してカスタムコントローラを作成します。
rails generate devise:controllers [scope]
スコープにusersを指定すると、app/controllers/users/
にコントローラが作成されます。そして、セッションコントローラは以下のようになります。
class Users::SessionsController < Devise::SessionsController
# GET /resource/sign_in
# def new
# super
# end
...
end
(コントローラを指定するには -c フラグを使用します。
例: rails generate devise:controllers users -c=sessions
)
2. ルータにこのコントローラを使用するように指示します。
devise_for :users, controllers: { sessions: 'users/sessions' }
3. devise/sessionsからusers/sessionsにビューをコピーします。
コントローラが変更されたので、devise/sessionsにあるデフォルトのビューは使用されません。
4. 最後に、目的のコントローラアクションを変更または拡張します。
コントローラのアクションを完全に上書きすることができます。
class Users::SessionsController < Devise::SessionsController
def create
# custom sign-in code
end
end
あるいは、単純に新しい動作を追加することもできます。
class Users::SessionsController < Devise::SessionsController
def create
super do |resource|
BackgroundWorker.trigger(resource)
end
end
end
これは、特定のアクション中にバックグラウンドジョブをトリガーしたり、イベントをログに記録したりするのに便利です。
Devise は、サインインが成功したか失敗したかをユーザーに知らせるためにフラッシュメッセージを使用していることを覚えておいてください。Devise は、アプリケーションが flash[:notice]
と flash[:alert]
を適切に呼び出すことを期待しています。フラッシュハッシュ全体を表示せず、特定のキーのみを表示してください。状況によっては、Devise はフラッシュハッシュに :timedout
キーを追加しますが、これは表示用ではありません。ハッシュ全体を印刷する場合は、このキーをハッシュから削除してください。
Configuring routes
Devise にはデフォルトのルートも含まれています。それらをカスタマイズする必要がある場合は、おそらく devise_for
メソッドを使ってカスタマイズすることができるはずです。これは :class_name
や :path_prefix
などのオプションを受け付けており、I18n 用のパス名を変更することもできます。
devise_for :users, path: 'auth', path_names: { sign_in: 'login', sign_out: 'logout', password: 'secret', confirmation: 'verification', unlock: 'unblock', registration: 'register', sign_up: 'cmon_let_me_in' }
詳細は必ず devise_for のドキュメントを確認してください。
より深いカスタマイズが必要な場合、例えば "/users/sign_in"
以外に "/sign_in"
を許可するなど、通常のルートを作成して、ルータの devise_scope
ブロックでラップするだけです。
devise_scope :user do
get 'sign_in', to: 'devise/sessions#new'
end
このようにして、"/sign_in"
にアクセスしたときにスコープ :user
を使うように Devise に指示します。devise_scope
もルータと同じようにエイリアスされていることに注意してください。
I18n
Devise は、フラッシュキー :notice
と :alert
と合わせて、I18n を使用したフラッシュメッセージを使用します。アプリをカスタマイズするには、ロケールファイルを設定します。
en:
devise:
sessions:
signed_in: 'Signed in successfully.'
routes で指定された単数形の名前を使って、設定したリソースに基づいて異なるメッセージを作成することもできます。
en:
devise:
sessions:
user:
signed_in: 'Welcome user, you are signed in.'
admin:
signed_in: 'Hello admin!'
Deviseメーラーでは、似たようなパターンで件名メッセージを作成しています。
en:
devise:
mailer:
confirmation_instructions:
subject: 'Hello everybody!'
user_subject: 'Hello User! Please confirm your email'
reset_password_instructions:
subject: 'Reset instructions'
すべてのメッセージを確認するには、ロケールファイルを見てください。また、私たちのwikiにある多くの翻訳のうちの一つに興味があるかもしれません。
Test helpers
Devise には、コントローラと統合テスト用のテストヘルパーがいくつか含まれています。これらを使用するには、それぞれのモジュールをテストケース/仕様に含める必要があります。
Controller tests
コントローラテストでは、テストケースまたはその親である ActionController::TestCase スーパークラスに Devise::Test::IntegrationHelpers を含める必要があります。コントローラテストのスーパークラスが ActionDispatch::IntegrationTest に変更されたので、Rails のバージョンが 5 より前の場合は、代わりに Devise::Test::ControllerHelpers をインクルードしてください (詳細については、Integration tests のセクションを参照してください)。
class PostsControllerTest < ActionController::TestCase
include Devise::Test::IntegrationHelpers # Rails >= 5
end
class PostsControllerTest < ActionController::TestCase
include Devise::Test::ControllerHelpers # Rails < 5
end
RSpecを使用している場合は、spec/support/devise.rb
、または spec/spec_helper.rb
(rspec-rails
を使用している場合はspec/rails_helper.rb
)の中に以下のように記述します。
RSpec.configure do |config|
config.include Devise::Test::ControllerHelpers, type: :controller
config.include Devise::Test::ControllerHelpers, type: :view
end
このインクルードは、require 'rspec/rails'
ディレクティブの後で行われていることを確認してください。
これで、コントローラテストで sign_in
と sign_out
メソッドを使う準備ができました。
sign_in @user
sign_in @user, scope: :admin
Devise の内部コントローラや Devise を継承するコントローラをテストしている場合は、リクエストの前にどのマッピングを使用するかを Devise に伝える必要があります。Devise はこの情報をルータから取得しますが、コントローラのテストはルータを通過しないので、 明示的に指定する必要があります。たとえば、ユーザスコープをテストしているのであれば、単純に以下のようにします。
test 'GET new' do
# Mimic the router behavior of setting the Devise scope through the env.
@request.env['devise.mapping'] = Devise.mappings[:user]
# Use the sign_in helper to sign in a fixture `User` record.
sign_in users(:alice)
get :new
# assert something
end
Integration tests
統合テストヘルパーは、Devise::Test::IntegrationHelpers
モジュールを含めることで利用できます。
class PostsTests < ActionDispatch::IntegrationTest
include Devise::Test::IntegrationHelpers
end
これで、統合テストで以下の sign_in
と sign_out
メソッドを使うことができるようになりました。
sign_in users(:bob)
sign_in users(:bob), scope: :admin
sign_out :user
RSpecユーザはIntegrationHelpers
モジュールを :feature specs
に含めることができます。
RSpec.configure do |config|
config.include Devise::Test::IntegrationHelpers, type: :feature
end
コントローラテストとは異なり、統合テストではdevise.mapping
env
値を指定する必要はありません。
RSpecを使ったRails 3 - Rails 4コントローラのテストについては、wikiを参照してください。
OmniAuth
Devise には、他のプロバイダとの認証を行うための OmniAuth サポートが付属しています。これを使用するには、config/initializers/devise.rb
で OmniAuth の設定を指定するだけです。
config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
OmniAuthのサポートについてはwikiで詳しく説明されています。
Configuring multiple models
Devise では、好きなだけ Devise モデルを設定することができます。上記の User モデルに加えて、認証とタイムアウト機能だけの Admin モデルを設定したい場合は、以下のように実行してください。
# 必要なフィールドでマイグレーションを作成します。
create_table :admins do |t|
t.string :email
t.string :encrypted_password
t.timestamps null: false
end
# Admin モデルの内部
devise :database_authenticatable, :timeoutable
# routes に
devise_for :admins
# protected controller に
before_action :authenticate_admin!
# コントローラとビュー に
admin_signed_in?
current_admin
admin_session
あるいは、単にDeviseジェネレーターを実行することもできます。
それらのモデルには完全に異なるルートがあることを心に留めておいてください。サインインやサインアウトなどのために同じコントローラを共有することはできませんし、できません。異なるロールで同じアクションを共有させたい場合は、ロールカラムを提供するか、認証用の専用gemを使用してロールベースのアプローチを使用することをお勧めします。
ActiveJob Integration
キューイングバックエンドを通してバックグラウンドでActionMailerメッセージを配信するためにRails 4.2とActiveJobを使用している場合、モデル内のsend_devise_notificationメソッドをオーバーライドすることで、既存のキューを通してDeviseメールを送信することができます。
def send_devise_notification(notification, *args)
devise_mailer.send(notification, self, *args).deliver_later
end
Password reset tokens and Rails logs
Recoverable モジュールを有効にしている場合、盗まれたパスワードリセットトークンが攻撃者にあなたのアプリケーションにアクセスされる可能性があることに注意してください。Deviseはランダムで安全なトークンを生成するために努力しており、トークンのダイジェストのみをデータベースに保存し、プレーンテキストは保存しません。しかし、Railsのデフォルトのロギング動作により、プレーンテキストトークンがログファイルに漏れてしまう可能性があります。
- Action Mailerは、すべての送信メールの内容をDEBUGレベルに丸ごとログに記録します。電子メールでユーザーに配信されたパスワードリセットトークンが漏洩します。
- アクティブジョブは、すべてのエンキューされたジョブへのすべての引数を INFO レベルでログに記録します。パスワード リセット メールを送信するために
deliver_later
を使用するように Devise を設定すると、パスワード リセット トークンが漏洩します。
Railsでは、本番用ロガーのレベルがデフォルトでDEBUGに設定されています。トークンがログに漏れないようにしたい場合は、プロダクションロガーのレベルをWARNに変更することを検討してください。
config.log_level = :warn
Other ORMs
Devise は ActiveRecord (デフォルト) と Mongoid をサポートしています。他の ORM を選択するには、初期化ファイルでそれを要求するだけです。
Rails API Mode
Rails 5+にはAPIとして使用するためにRailsを最適化するAPIモードが組み込まれています(APIモードのみ)。Deviseは、例外などを発生させないという意味で、このモードで構築されたアプリケーションを追加の修正なしにある程度扱えるようになっています。しかし、この互換性の完全な範囲がまだわかっていないため、開発/テスト中にいくつかの問題が発生するかもしれません。(詳細は issue #4947 を参照してください)
サポートされている認証戦略
API のみのアプリケーションは、クッキーによるブラウザベースの認証をサポートしていません。しかし、devise は HTTP Basic Auth を使用し、各リクエストでユーザを認証する http_authenticatable 戦略を使用して、そのような場合でもすぐに認証を提供することができます。(詳細については、How To: Use HTTP Basic Authentication のwiki記事を参照してください)
HTTP Auth のデバイスのデフォルトは無効になっているので、データベースストラテジーのデバイス初期化で有効にする必要があります。
config.http_authenticatable = [:database]
この制限は、アプリケーション内で、または gem ベースの拡張機能を使用してデバイスにカスタムウォーデン戦略を実装することを制限するものではありません。API の一般的な認証ストラテジーはトークンベースの認証です。このタイプの認証やその他の認証をサポートするためにdeviseを拡張することの詳細については、シンプルなトークン認証の例と代替案についてのwiki記事や、Deviseを使ったカスタム認証方法についてのこのブログ記事を参照してください。
Testing
APIモードではミドルウェアスタックの順番が変わるため、Devise::Test::IntegrationHelpers
で問題が発生する可能性があります。この問題は通常、#sign_in
のような統合テストヘルパーを使用している場合、nil:NilClass
のための未定義メソッド ``[]='` エラーとして表面化します。
解決策は、以下を test.rb に追加してミドルウェアを並べ替えるだけです。
Rails.application.config.middleware.insert_before Warden::Manager, ActionDispatch::Cookies
Rails.application.config.middleware.insert_before Warden::Manager, ActionDispatch::Session::CookieStore
これについての理解を深めるには、この問題を確認してください。
さらに、ビューがサポートされていない場合、現時点では、Confirmable、Recoverable、Lockableからの一部のメールベースのフローは直接サポートされていないことに注意してください。
以上
以上です。結構難解な Getting started ですね……。
網羅性が高い分、使い始めるのには不要な情報が多いというか……😭
Discussion