Как использовать динамическую область видимости с 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 5

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