Как использовать динамическую область видимости с devise и omniauth
Я обновляю старое приложение с rails 3.0 до rails 4.1 и испытываю проблемы с настройкой маршрутов для devise и omniauth. В настоящее время маршруты выглядят следующим образом:
scope "(:locale)", locale: /#{I18n.available_locales.join("|")}/ do
devise_for :users, controllers: {
omniauth_callbacks: "users/omniauth_callbacks"
}
Когда я запускаю это, я получаю следующую ошибку:
Devise does not support scoping omniauth callbacks under a dynamic segment (RuntimeError)
and you have set "/(:locale)/users". You can work around by passing
`skip: :omniauth_callbacks` and manually defining the routes. Here is an example:
match "/users/auth/:provider",
constraints: { provider: /google|facebook/ },
to: "devise/omniauth_callbacks#passthru",
as: :omniauth_authorize,
via: [:get, :post]
match "/users/auth/:action/callback",
constraints: { action: /google|facebook/ },
to: "devise/omniauth_callbacks",
as: :omniauth_callback,
via: [:get, :post]
Я пытался вручную определить маршруты несколькими способами, но при выполнении тестов ни один из моих маршрутов не работает. Знает ли кто-нибудь правильный способ обработки этих динамических сегментов с помощью devise_for?
2 ответа:
Я добавил devise_for 2 раза в маршрутах.rb
devise_for :users, skip: [:session, :password, :registration], controllers: { omniauth_callbacks: "users/omniauth_callbacks" } scope ":locale", locale: /#{I18n.available_locales.join("|")}/ do devise_for :users, skip: [:omniauth_callbacks]
Нашел ответ здесь
Кроме того, вам нужен пользовательский блок сбоев для omniauth для обработки ошибок во время входа в систему (например, пользователь отменяет):
# In config/initializers/omniauth.rb require 'devise/omniauth' # Work around for bug when scoping paths # See: https://github.com/spree/spree_social/issues/130 OmniAuth.config.on_failure = Proc.new do |env| env['devise.mapping'] = Devise.mappings[:user] controller_name = ActiveSupport::Inflector.camelize(env['devise.mapping'].controllers[:omniauth_callbacks]) controller_klass = ActiveSupport::Inflector.constantize("#{controller_name}Controller") controller_klass.action(:failure).call(env) end
Я хотел бы добавить к решению, представленному на wiki devise: https://github.com/plataformatec/devise/wiki/How-To:-OmniAuth-inside-localized-scope
Если вы уже используете этап настройки (
setup: true
в devise.rb), вы можете пропустить создание нового контроллера (omniauth_controller.rb
в их примере) и просто добавитьsession[:omniauth_login_locale] = I18n.locale
к действиюsetup
. В конечном итоге мойroutes.rb
выглядит так:devise_for :users, skip: [:session, :password, :registration, :confirmation], controllers: { omniauth_callbacks: 'omniauth_callbacks' } scope '(:locale)', locale: /en|zh/ do devise_for :users, skip: :omniauth_callbacks devise_scope :user do get 'auth/:provider/setup' => 'omniauth_callbacks#setup' end end