- Ruby / Rails関連
READ MORE
こんにちは、hachi8833です。
Devise gemのWiki How-To翻訳、第2弾です。DeviseもRails 5.1対応で忙しそうですね。
原文が更新されていることにお気づきの場合は、ぜひ@techrachoまでお知らせください。更新いたします。
Deviseで使うロール(役割)が1つしかない状態で、ログイン(sign in)とログアウト用(sign out)のルーティングをデフォルトの /users/sign_in
や/users/sign_out
から/login
や/logout
に変更したいことがあります。
これはデフォルトのままのDeviseではできません。Deviseは、URLをチェックすることによってユーザーのアクセスするスコープを決定するからです。URLが/users/login
であればスコープはuser
であることがDevise側でわかりますが、/login
にアクセスすると、使われるべきスコープをDevise側で決定できません。幸いなことに、Deviseにはデフォルトスコープを指定するしくみがあるので、これによってURLを短くできます。
この設定は、アクセスに使うURLをルーティングのdevise_scope
に記述するだけで完了します。
devise_scope :user do
get 'login', to: 'devise/sessions#new'
end
以下のように、devise_scope
のエイリアスであるas
も使えます。
as :user do
get 'login', to: 'devise/sessions#new'
end
sign_out
の場合は次のようにします。
devise_scope :user do
delete 'logout', to: 'devise/sessions#destroy'
end
次のようにskip:
オプションですべてのセッションルーティングをスキップし、必要なルーティングだけを定義することもできます。
devise_for :users, skip: [:sessions]
as :user do
get 'signin', to: 'devise/sessions#new', as: :new_user_session
post 'signin', to: 'devise/sessions#create', as: :user_session
delete 'signout', to: 'devise/sessions#destroy', as: :destroy_user_session
end
このようにすると、#authenticate_user!
などのヘルパーを使ったときに、定義済みの正しいカスタムページにユーザーをリダイレクトできます。
ただし、:sign_out_via
という設定オプションを使っていると上のsignout
アクションがエラーになることがあります。その場合は、デフォルトの動作を複製して次のように:sign_out_via
によってdelete
をget
に変更します。
devise_for :users, skip: [:sessions]
as :user do
get 'signin', to: 'devise/sessions#new', as: :new_user_session
post 'signin', to: 'devise/sessions#create', as: :user_session
match 'signout', to: 'devise/sessions#destroy', as: :destroy_user_session, via: Devise.mappings[:user].sign_out_via
end
#devise_for
メソッドにはこういうときに便利なオプションパラメータが多数用意されています。
たとえば、users
という名前空間をすべてのルーティングから取り除き、sign_in
とsign_out
をそれぞれlogin
とlogout
に置き換えるには、次のようにします。
devise_for :users, path: '', path_names: { sign_in: 'login', sign_out: 'logout'}
ただし、Deviseで複数のコントローラ(パスワード用など)を使いたい場合は、最初の方法を使う必要があります。
上記の sign_out_via
に関連してすこし補足です。
Deviseではログインセッションをsessionという概念で管理しており、RESTful的には「新規sessionを作る(Devise::SessionsController#create)=ログインする」といった抽象化がされています。
そのため「ログアウトする」はsessionを破棄する、すなわちsessionの削除(Devise::SessionsController#destroy)というインターフェースになっています。
このとき、確かにsession削除はDELETEメソッドで呼ばれるのがRESTの概念上あるべき姿なのですが「ログアウトする」という機能自体はRailsの外から呼びたかったり、リダイレクト処理の中で強制ログアウトさせたいといったケースが考えられるため、DELETEメソッドよりもGETメソッドでログアウトできた方が便利です( _method=delete
とか付ければGETでもDELETEメソッドにbypassできますが、いちいち考えるのが面倒)。
というわけで、以下の様に sign_out_via
を設定してやることで、ログアウトについてはGETリクエストで処理でき、 link_to
ヘルパでも単なる destroy_user_session_path
へのリンクとして記述できるようになります。
Devise.config.sign_out_via = :get
= link_to 'ログアウト', destroy_user_path