yamotonalds's blog

Webアプリケーション開発における技術メモが中心です。たまにWebサービス、興味を持ったデバイス、自作PCに関する話題もあるかも。Amazon好きなのでAmazon.co.jpアソシエイト使ってます。

deviseでlocaleが維持されない場合があったので対処

ユーザー認証にdeviseを使っているのだけれどlocaleパラメーターがデフォルトのlocaleに戻ってしまう場合があった。

具体的には既にログインしている状態でsign_in,sign_upページに遷移しようとした場合。リダイレクトされて「You are already signed in.」というフラッシュメッセージが表示されるのだけれどlocaleをjpにして遷移してもリダイレクト後のページはデフォルトのlocaleのページになってしまう。

 

公式Wikiに How To: Redirect with locale after authentication failure というのがあるけれど認証に失敗している訳ではないしその通りにしても効果無し。

処理を追いかけてみたところI18n.localeを設定しているフィルターが実行される前にリダイレクトされている模様。deviseのソースコード(v2.2.4)を見てみるとDevise::RegistrationsControllerでprepend_before_filterされているrequire_no_authenticationでリダイレクトされていた。

 

なんとかしてlocaleを設定する(set_locale)フィルターをrequire_no_authenticationフィルターより先に実行したいのだが…良い方法がわからなかった。

ApplicationControllerでprepend_before_filter: :set_localeとしてもDevise::*ControllerはApplicationControllerを継承したDeviseControllerを継承してprepend_before_filter: :require_no_authenticationしているのでrequire_no_authenticationが先に実行されてしまう。

しかたがないのでDivese::*Controllerを継承したControllerを用意してprependし直すことにした。

# config/routes.rb
scope '(:locale)' do
  devise_for :users,
    :skip => [:registration],
    :controllers => {
      :sessions => "mydevise/sessions",
      :passwords => "mydevise/passwords",
      :unlocks => "mydevise/unlocks",
    }
  devise_scope :user do
    resource :registration,
      only: [:new, :create, :edit, :update],
      path: 'users',
      path_names: { new: 'sign_up' },
      controller: 'mydevise/registrations',
      as: :user_registration do
        get :cancel
      end
  end
end
# app/controllers/mydevise/sessions_controller.rb
# 他のDevise::*Controllerも同様
class Mydevise::SessionsController < Devise::SessionsController
  skip_before_filter :set_locale
  prepend_before_filter :set_locale
end

 とりあえずこれでlocaleは維持されるようになったが…どなたかもっと良い解決方法をご存知の方がおられましたらお教えください。