Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rails Engine + OmniAuth = undefined method and no route matches #2692

Closed
jirikolarik opened this issue Oct 18, 2013 · 11 comments
Closed

Rails Engine + OmniAuth = undefined method and no route matches #2692

jirikolarik opened this issue Oct 18, 2013 · 11 comments

Comments

@jirikolarik
Copy link

Hi, I just created RailsEngine with OmniAuth.

My engine is called Auth.
I added - lib/auth.rb

require 'devise'

config/routes.rb

  devise_for  :users, class_name: 'Auth::User', module: :devise, 
              controllers: { omniauth_callbacks: 'auth/omniauth_callbacks' }

And I configured initializers/devise.rb like this

config.router_name = :auth
config.omniauth_path_prefix = '/auth/users/auth'

But when I visit /auth/users/sign_in, it raise error

undefined method `user_omniauth_authorize_path' for #<#<Class:0x007fb78db4ed70>:0x007fb78db4dfb0>

So I rewrote view and linked it directly to '/auth/users/auth/twitter'
This redirects me to twitter and when I confirm the dialog, it redirects me back and raise

No route matches [GET] "/auth/users/auth/twitter/callback"

This route doesn't exist, but exist: '/auth/auth/users/auth/twitter/callback'

root GET /     home#index
auth     /auth Auth::Engine

Routes for Auth::Engine:
        new_user_session GET      /users/sign_in(.:format)                    devise/sessions#new
            user_session POST     /users/sign_in(.:format)                    devise/sessions#create
    destroy_user_session DELETE   /users/sign_out(.:format)                   devise/sessions#destroy
           user_password POST     /users/password(.:format)                   devise/passwords#create
       new_user_password GET      /users/password/new(.:format)               devise/passwords#new
      edit_user_password GET      /users/password/edit(.:format)              devise/passwords#edit
                         PATCH    /users/password(.:format)                   devise/passwords#update
                         PUT      /users/password(.:format)                   devise/passwords#update
cancel_user_registration GET      /users/cancel(.:format)                     devise/registrations#cancel
       user_registration POST     /users(.:format)                            devise/registrations#create
   new_user_registration GET      /users/sign_up(.:format)                    devise/registrations#new
  edit_user_registration GET      /users/edit(.:format)                       devise/registrations#edit
                         PATCH    /users(.:format)                            devise/registrations#update
                         PUT      /users(.:format)                            devise/registrations#update
                         DELETE   /users(.:format)                            devise/registrations#destroy
       user_confirmation POST     /users/confirmation(.:format)               devise/confirmations#create
   new_user_confirmation GET      /users/confirmation/new(.:format)           devise/confirmations#new
                         GET      /users/confirmation(.:format)               devise/confirmations#show
             user_unlock POST     /users/unlock(.:format)                     devise/unlocks#create
         new_user_unlock GET      /users/unlock/new(.:format)                 devise/unlocks#new
                         GET      /users/unlock(.:format)                     devise/unlocks#show
 user_omniauth_authorize GET|POST /auth/users/auth/:provider(.:format)        auth/omniauth_callbacks#passthru {:provider=>/twitter/}
  user_omniauth_callback GET|POST /auth/users/auth/:action/callback(.:format) auth/omniauth_callbacks#(?-mix:twitter)

when I remove

config.omniauth_path_prefix = '/auth/users/auth'

then is callback route generated properly

 user_omniauth_authorize GET|POST /users/auth/:provider(.:format)        auth/omniauth_callbacks#passthru {:provider=>/twitter/}
  user_omniauth_callback GET|POST /users/auth/:action/callback(.:format) auth/omniauth_callbacks#(?-mix:twitter)

But it raise

Not found. Authentication pass thru.

When I access '/auth/users/auth/twitter'

I'm running on Rails 4 and Ruby 2

@josevalim
Copy link
Contributor

You are right. This is wrong. If we are inside an engine, we most likely don't want the omniauth path prefix to reflect inside the engine. I am unsure on how to fix this for now so I recommend you to simply define the routes manually meanwhile:

https://github.com/plataformatec/devise/blob/master/lib/devise/rails/routes.rb#L387-L397

@jirikolarik
Copy link
Author

Thanks for your answer and pointing me to the source of problems.

I don't think, it's the best idea, but it fixed routes

def devise_omniauth_callback(mapping, controllers) #:nodoc:
    path, @scope[:path] = @scope[:path], nil
    # path_prefix = Devise.omniauth_path_prefix || "/#{mapping.path}/auth".squeeze("/") # Temporary fixed
    path_prefix, callback_prefix = Devise.omniauth_path_prefix, "/#{mapping.path}/auth".squeeze("/")
    set_omniauth_path_prefix!(path_prefix)

    providers = Regexp.union(mapping.to.omniauth_providers.map(&:to_s))

    match "#{path_prefix}/:provider",
      :constraints => { :provider => providers },
      :to => "#{controllers[:omniauth_callbacks]}#passthru",
      :as => :omniauth_authorize,
      :via => [:get, :post]

    match "#{callback_prefix}/:action/callback",
      :constraints => { :action => providers },
      :to => controllers[:omniauth_callbacks],
      :as => :omniauth_callback,
      :via => [:get, :post]
  ensure
    @scope[:path] = path
  end

This is how I actually fix that

devise_scope :user do 
  providers = Regexp.union(Devise.omniauth_providers.map(&:to_s))
  match 'users/auth/:provider', 
    constraints: { provider: providers },
    to: 'omniauth_callbacks#passthru', 
    as: :omniauth_authorize, 
    via: [:get, :post]

  match 'users/auth/:action/callback', 
    constraints: { action: providers },
    to: 'omniauth_callbacks', 
    as: :omniauth_callback, 
    via: [:get, :post]
end
devise_for  :users, class_name: 'Auth::User', module: :devise

@benebrice
Copy link

Hello,

I have almost the same problem with

  • devise_for :users, :controllers => { omniauth_callbacks: 'users/omniauth_callbacks', confirmations: 'users/confirmations'}

There is not any routes created and visible thanks to rake routes.

I am not using an engine like previously.

This code was working with Rails 3.2.12, Ruby 1.9.3, devise 2.2.3.

Now I am using Rails 4.0.2, Ruby 2.1 and, obviously devise 3.2.2.

@tmandry
Copy link

tmandry commented Apr 19, 2014

Was also bit by this issue in 3.2.4. My workaround was to add this to routes (note I had to prefix helpers with user_):

  devise_scope :user do
    match "/users/auth/:provider",
      constraints: { provider: /google|facebook/ },
      to: "users/omniauth_callbacks#passthru",
      as: :user_omniauth_authorize,
      via: [:get, :post]
    match "/users/auth/:action/callback",
      constraints: { action: /google|facebook/ },
      to: "users/omniauth_callbacks",
      as: :user_omniauth_callback,
      via: [:get, :post]
  end

and this to my Devise initializer:

  Rails.application.config.after_initialize do
    ::OmniAuth::config.path_prefix = config.omniauth_path_prefix = "#{Ares.path_prefix}/users/auth"
  end

where Ares.path_prefix is a setting set by the application to tell the engine its path prefix.

@lailsonbm
Copy link

Thanks, @jirikolarik and @tmandry, the code worked for me too. But it would be nice if it worked without hacks, out of the box. =)

@terenceponce
Copy link

Is this still working? I tried the solution mentioned here, but I got nothing. Also, looking at the solution here and the current code base, it looks like this was already implemented inside Devise.

I've opened a question on SO: http://stackoverflow.com/questions/25151273/not-found-authentication-passthru-error-devise-omniauthable-module-doesnt

gogo52cn added a commit to gogo52cn/spree that referenced this issue Dec 30, 2014
gogo52cn added a commit to gogo52cn/spree_social that referenced this issue Dec 30, 2014
@chibicode
Copy link

For me, I didn't have this issue - maybe it's because I mounted my engine at the root level, per this article (see "Routes" section):
http://tech.taskrabbit.com/blog/2014/02/11/rails-4-engines/

Devise version: 3.2.4
Omniauth version: 1.1.4

# Main Routes
mount MyEngine::Engine, at: "/"
# Model

module MyEngine
  class Account < ActiveRecord::Base
    devise :omniauthable, omniauth_providers: %I(google_oauth2)
  end
end
# Controller
module MyEngine
  module Accounts
    class OmniauthCallbacksController < Devise::OmniauthCallbacksController
      def google_oauth2
        ...
      end
    end
  end
end
# Config
config.omniauth_path_prefix = "/my_engine/accounts/auth"
# Routes
MyEngine::Engine.routes.draw do
  scope :my_engine do
    devise_for :accounts, class_name: "MyEngine::Account",
                          module: :devise,
                          controllers: { omniauth_callbacks: "my_engine/accounts/omniauth_callbacks" }
<!-- View -->
<%= link_to account_omniauth_authorize_path(provider: :google_oauth2) ... %>

@mspanc
Copy link

mspanc commented Feb 6, 2015

I have the same issue. Mounting engine that uses devise + oauth under different path than "/" causes "Not found, authentication pass thru" error.

I've tried setting OmniAuth::config.path_prefix = config.omniauth_path_prefix = to include mounting path, but without success.

The workaround I've found is to mount engine at "/" and use namespaces, such as:

MyEngine::MySubModule::Engine.routes.draw do
  namespace :my_engine do
    namespace :my_submodule do
      devise_for :user_accounts,
        sign_out_via: [ :post, :delete ],
        class_name: "::MyEngine::MySubmodule::UserAccount",
        format: false,
        controllers: { 
          sessions: "my_engine/my_submodule/sessions", 
          passwords: "my_engine/my_submodule/passwords", 
          registrations: "my_engine/my_submodule/registrations", 
          omniauth_callbacks: "my_engine/my_submodule/omniauth_callbacks", 
          unlocks: "my_engine/my_submodule/unlocks" }

    end
  end
end

Devise 3.4.1, omniauth 1.2.2, rails 4.2.0.

@tianlitao
Copy link

I have the same promble,and use @tmandry way,there is a place to watch.

devise.rb
  Rails.application.config.after_initialize do
    ::OmniAuth::config.path_prefix = config.omniauth_path_prefix = "/backend/users/auth"
  end

@tegon
Copy link
Member

tegon commented Dec 6, 2017

I'm closing this issue because it has not had recent activity.
If you're still facing this on the latest version, please open a new one with all the information requested in the template.
Thank you!

@ndvbd
Copy link

ndvbd commented Feb 13, 2022

I am getting

The action 'facebook' could not be found for Devise::OmniauthCallbacksController

And don't know how to even debug it...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests