Search code examples
ruby-on-railsrubydeviseomniauthomniauth-linkedin

Uninitialized constant OmniauthCallbacksController when trying to sign up user


I'm having an issue with getting OmniAuth to work. I've been following this tutorial here to try and implement it with my existing app, but am coming up with the ActionController::RoutingError at /users/auth/github/upgrade uninitialized constant OmniauthCallbacksController error. I've looked at several other SO posts but most of those answers deal with misspellings and I've triple-checked that everything is spelled correctly. What might be interfering?

User Model:

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
                 :recoverable, :rememberable, :trackable, :omniauthable

  has_many :identities

  def github
        identities.where( :provider => "github" ).first
    end

    def github_client
        @github_client ||= Github.client( access_token: github.accesstoken )
    end

    def linkedin
        identities.where( :provider => "linkedin" ).first
    end

    def linkedin_client
        @linkedin_client ||= Linkedin.client( access_token: linkedin.accesstoken )
    end
end

Identity Model:

class Identity < ActiveRecord::Base
  belongs_to :user
  validates_presence_of :uid, :provider
  validates_uniqueness_of :uid, :scope => :provider

  def self.find_for_oauth(auth)
    identity = find_by(provider: auth.provider, uid: auth.uid)
    identity = create(uid: auth.uid, provider: auth.provider) if identity.nil?
    identity.accesstoken = auth.credentials.token
    identity.refreshtoken = auth.credentials.refresh_token
    identity.name = auth.info.name
    identity.email = auth.info.email
    identity.nickname = auth.info.nickname
    identity.image = auth.info.image
    identity.phone = auth.info.phone
    identity.urls = (auth.info.urls || "").to_json
    identity.save
    identity
  end
end

Devise Model:

Devise.setup do |config|

  # config.omniauth :google_oauth2, ENV['GOOGLE_OAUTH2_APP_ID'], ENV['GOOGLE_OAUTH2_APP_SECRET'], scope: "email,profile,offline", prompt: "consent"
  config.omniauth :github, ENV['GITHUB_APP_ID'], ENV['GITHUB_APP_SECRET'], setup: true
  # config.omniauth :facebook, ENV['FACEBOOK_APP_ID'], ENV['FACEBOOK_APP_SECRET'], scope: "email"
  config.omniauth :linkedin, ENV['LINKEDIN_APP_ID'], ENV['LINKEDIN_APP_SECRET'], setup: true

Omniauth Model:

Rails.application.config.middleware.use OmniAuth::Builder do

  provider :github, ENV['GITHUB_KEY'], ENV['GITHUB_SECRET']
  provider :linkedin, ENV['LINKEDIN_KEY'], ENV['LINKEDIN_SECRET']
end

FormUser Model

class FormUser < User
  attr_accessor :current_password

  validates_presence_of   :email, if: :email_required?
  validates_uniqueness_of :email, allow_blank: true, if: :email_changed?
  validates_format_of     :email, with: Devise.email_regexp, allow_blank: true, if: :email_changed?

  validates_presence_of     :password, if: :password_required?
  validates_confirmation_of :password, if: :password_required?
  validates_length_of       :password, within: Devise.password_length, allow_blank: true

  def password_required?
    return false if email.blank?
    !persisted? || !password.nil? || !password_confirmation.nil?
  end

  def email_required?
    true
  end
end

Omniauth Callbacks Controller:

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def instagram
    generic_callback( 'instagram' )
  end

  def facebook
    generic_callback( 'facebook' )
  end

  def twitter
    generic_callback( 'twitter' )
  end

  def google_oauth2
    generic_callback( 'google_oauth2' )
  end

  def generic_callback( provider )
    @identity = Identity.find_for_oauth env["omniauth.auth"]

    # @user = @identity.user || current_user
    @user = @identity.user || User.find_by(email: @identity.email) || current_user
    if @user.nil?
      @user = User.create( email: @identity.email || "" )
      @identity.update_attribute( :user_id, @user.id )
    end

    if @user.email.blank? && @identity.email
      @user.update_attribute( :email, @identity.email)
    end

    if @user.persisted?
      @identity.update_attribute( :user_id, @user.id )
      # This is because we've created the user manually, and Device expects a
      # FormUser class (with the validations)
      @user = FormUser.find @user.id
      sign_in_and_redirect @user, event: :authentication
      set_flash_message(:notice, :success, kind: provider.capitalize) if is_navigational_format?
    else
      session["devise.#{provider}_data"] = env["omniauth.auth"]
      redirect_to new_user_registration_url
    end
  end

  def upgrade
    scope = nil
    if params[:provider] == "google_oauth2"
      scope = "email,profile,offline,https://www.googleapis.com/auth/admin.directory.user"
    end

    redirect_to user_omniauth_authorize_path( params[:provider] ), flash: { scope: scope }
  end

  def setup
    request.env['omniauth.strategy'].options['scope'] = flash[:scope] || request.env['omniauth.strategy'].options['scope']
    render :text => "Setup complete.", :status => 404
  end
end

Registrations Controller:

class Users::RegistrationsController < Devise::RegistrationsController
  def create

    unless params["user"]["code"] == ENV["CODE_TO_SIGN_UP"]
      respond_to do |format|
        format.html { return redirect_to new_user_registration_path, notice: 'The code you entered was wrong. Please contact ' + ENV["ADMIN_EMAIL"] }
      end
    end

    super
  end

  def update_resource(resource, params)
    if resource.encrypted_password.blank? # || params[:password].blank?
      resource.email = params[:email] if params[:email]
      if !params[:password].blank? && params[:password] == params[:password_confirmation]
        logger.info "Updating password"
        resource.password = params[:password]
        resource.save
      end
      if resource.valid?
        resource.update_without_password(params)
      end
    else
      resource.update_with_password(params)
    end
  end

Routes

Rails.application.routes.draw do
devise_for :users, class_name: 'FormUser', :controllers => { 
    omniauth_callbacks: 'users/omniauth_callbacks',
    registrations: 'users/registrations'
  }

  devise_scope :user do
    get '/users/auth/:provider/upgrade' => 'omniauth_callbacks#upgrade', as: :user_omniauth_upgrade
    get '/users/auth/:provider/setup', :to => 'omniauth_callbacks#setup'
  end

end

UPDATE rake routes:

Prefix Verb     URI Pattern                             Controller#Action
                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_github_omniauth_authorize GET|POST /users/auth/github(.:format)            users/omniauth_callbacks#passthru
   user_github_omniauth_callback GET|POST /users/auth/github/callback(.:format)   users/omniauth_callbacks#github
user_linkedin_omniauth_authorize GET|POST /users/auth/linkedin(.:format)          users/omniauth_callbacks#passthru
 user_linkedin_omniauth_callback GET|POST /users/auth/linkedin/callback(.:format) users/omniauth_callbacks#linkedin
                   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)                 users/registrations#cancel
               user_registration POST     /users(.:format)                        users/registrations#create
           new_user_registration GET      /users/sign_up(.:format)                users/registrations#new
          edit_user_registration GET      /users/edit(.:format)                   users/registrations#edit
                                 PATCH    /users(.:format)                        users/registrations#update
                                 PUT      /users(.:format)                        users/registrations#update
                                 DELETE   /users(.:format)                        users/registrations#destroy
           user_omniauth_upgrade GET      /users/auth/:provider/upgrade(.:format) users/omniauth_callbacks#upgrade
                                 GET      /users/auth/:provider/setup(.:format)   users/omniauth_callbacks#setup
                    typing_tests GET      /typing_tests(.:format)                 typing_tests#index
                                 POST     /typing_tests(.:format)                 typing_tests#create
                 new_typing_test GET      /typing_tests/new(.:format)             typing_tests#new
                edit_typing_test GET      /typing_tests/:id/edit(.:format)        typing_tests#edit
                     typing_test GET      /typing_tests/:id(.:format)             typing_tests#show
                                 PATCH    /typing_tests/:id(.:format)             typing_tests#update
                                 PUT      /typing_tests/:id(.:format)             typing_tests#update
                                 DELETE   /typing_tests/:id(.:format)             typing_tests#destroy
                         prompts GET      /prompts(.:format)                      prompts#index
                                 POST     /prompts(.:format)                      prompts#create
                      new_prompt GET      /prompts/new(.:format)                  prompts#new
                     edit_prompt GET      /prompts/:id/edit(.:format)             prompts#edit
                          prompt GET      /prompts/:id(.:format)                  prompts#show
                                 PATCH    /prompts/:id(.:format)                  prompts#update
                                 PUT      /prompts/:id(.:format)                  prompts#update
                                 DELETE   /prompts/:id(.:format)                  prompts#destroy
                    universities GET      /universities(.:format)                 universities#index
                                 POST     /universities(.:format)                 universities#create
                  new_university GET      /universities/new(.:format)             universities#new
                 edit_university GET      /universities/:id/edit(.:format)        universities#edit
                      university PATCH    /universities/:id(.:format)             universities#update
                                 PUT      /universities/:id(.:format)             universities#update
                                 DELETE   /universities/:id(.:format)             universities#destroy
                        programs GET      /programs(.:format)                     programs#index
                                 POST     /programs(.:format)                     programs#create
                     new_program GET      /programs/new(.:format)                 programs#new
                    edit_program GET      /programs/:id/edit(.:format)            programs#edit
                         program PATCH    /programs/:id(.:format)                 programs#update
                                 PUT      /programs/:id(.:format)                 programs#update
                                 DELETE   /programs/:id(.:format)                 programs#destroy
                           users GET      /users(.:format)                        users#index
                       edit_user GET      /users/:id/edit(.:format)               users#edit
                            user GET      /users/:id(.:format)                    users#show
                                 PATCH    /users/:id(.:format)                    users#update
                                 PUT      /users/:id(.:format)                    users#update
                                 DELETE   /users/:id(.:format)                    users#destroy
                            root GET      /                                       typing_tests#index
            unauthenticated_root GET      /                                       devise/sessions#new

Stack trace:

Started GET "/" for 127.0.0.1 at 2017-05-03 18:24:26 -0500
  ActiveRecord::SessionStore::Session Load (0.5ms)  SELECT  "sessions".* FROM "sessions"  WHERE "sessions"."session_id" = '430aa65b41ec7892dd1581f14a9fbd16'  ORDER BY "sessions"."id" ASC LIMIT 1
Processing by Devise::SessionsController#new as HTML
  Rendered devise/shared/_links.html.erb (0.3ms)
  Rendered devise/sessions/new.html.erb within layouts/application (4.5ms)
Completed 200 OK in 90ms (Views: 88.9ms | ActiveRecord: 0.0ms)
   (0.1ms)  BEGIN
  SQL (0.3ms)  UPDATE "sessions" SET "data" = $1, "updated_at" = $2 WHERE "sessions"."id" = 45  [["data", "BAh7BkkiEF9jc3JmX3Rva2VuBjoGRUZJIjFjakIxRFIwRzIxaEl6SkZoNEsv\nMVdGeHZUSGNUS0R0d3cxWFB3aENBbWVjPQY7AEY=\n"], ["updated_at", "2017-05-03 23:24:26.682877"]]
   (6.5ms)  COMMIT


Started GET "/users/auth/github/upgrade" for 127.0.0.1 at 2017-05-03 18:24:27 -0500
Processing by Users::OmniauthCallbacksController#upgrade as HTML
  Parameters: {"provider"=>"github"}
Completed 500 Internal Server Error in 19ms

NoMethodError - undefined method `user_omniauth_authorize_path' for #<Users::OmniauthCallbacksController:0x007f9a1e0012b0>
Did you mean?  user_omniauth_upgrade_path
               user_github_omniauth_authorize_path:
  app/controllers/users/omniauth_callbacks_controller.rb:51:in `upgrade'
  actionpack (4.1.9) lib/action_controller/metal/implicit_render.rb:4:in `send_action'
  actionpack (4.1.9) lib/abstract_controller/base.rb:189:in `process_action'
  actionpack (4.1.9) lib/action_controller/metal/rendering.rb:10:in `process_action'
  actionpack (4.1.9) lib/abstract_controller/callbacks.rb:20:in `block in process_action'
  activesupport (4.1.9) lib/active_support/callbacks.rb:113:in `call'
  activesupport (4.1.9) lib/active_support/callbacks.rb:149:in `block in halting_and_conditional'
  activesupport (4.1.9) lib/active_support/callbacks.rb:229:in `block in halting'
  activesupport (4.1.9) lib/active_support/callbacks.rb:166:in `block in halting'
  activesupport (4.1.9) lib/active_support/callbacks.rb:166:in `block in halting'
  activesupport (4.1.9) lib/active_support/callbacks.rb:166:in `block in halting'
  activesupport (4.1.9) lib/active_support/callbacks.rb:86:in `run_callbacks'
  actionpack (4.1.9) lib/abstract_controller/callbacks.rb:19:in `process_action'
  actionpack (4.1.9) lib/action_controller/metal/rescue.rb:29:in `process_action'
  actionpack (4.1.9) lib/action_controller/metal/instrumentation.rb:31:in `block in process_action'
  activesupport (4.1.9) lib/active_support/notifications.rb:159:in `block in instrument'
  activesupport (4.1.9) lib/active_support/notifications/instrumenter.rb:20:in `instrument'
  activesupport (4.1.9) lib/active_support/notifications.rb:159:in `instrument'
  actionpack (4.1.9) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
  actionpack (4.1.9) lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
  activerecord (4.1.9) lib/active_record/railties/controller_runtime.rb:18:in `process_action'
  actionpack (4.1.9) lib/abstract_controller/base.rb:136:in `process'
  actionview (4.1.9) lib/action_view/rendering.rb:30:in `process'
  actionpack (4.1.9) lib/action_controller/metal.rb:196:in `dispatch'
  actionpack (4.1.9) lib/action_controller/metal/rack_delegation.rb:13:in `dispatch'
  actionpack (4.1.9) lib/action_controller/metal.rb:232:in `block in action'
  actionpack (4.1.9) lib/action_dispatch/routing/route_set.rb:82:in `dispatch'
  actionpack (4.1.9) lib/action_dispatch/routing/route_set.rb:50:in `call'
  actionpack (4.1.9) lib/action_dispatch/routing/mapper.rb:45:in `call'
  actionpack (4.1.9) lib/action_dispatch/journey/router.rb:73:in `block in call'
  actionpack (4.1.9) lib/action_dispatch/journey/router.rb:59:in `each'
  actionpack (4.1.9) lib/action_dispatch/journey/router.rb:59:in `call'
  actionpack (4.1.9) lib/action_dispatch/routing/route_set.rb:685:in `call'
  omniauth (1.4.2) lib/omniauth/strategy.rb:186:in `call!'
  omniauth (1.4.2) lib/omniauth/strategy.rb:164:in `call'
  omniauth (1.4.2) lib/omniauth/strategy.rb:186:in `call!'
  omniauth (1.4.2) lib/omniauth/strategy.rb:164:in `call'
  meta_request (0.3.4) lib/meta_request/middlewares/app_request_handler.rb:13:in `call'
  meta_request (0.3.4) lib/meta_request/middlewares/meta_request_handler.rb:13:in `call'
  warden (1.2.6) lib/warden/manager.rb:35:in `block in call'
  warden (1.2.6) lib/warden/manager.rb:34:in `catch'
  warden (1.2.6) lib/warden/manager.rb:34:in `call'
  rack (1.5.5) lib/rack/etag.rb:23:in `call'
  rack (1.5.5) lib/rack/conditionalget.rb:25:in `call'
  rack (1.5.5) lib/rack/head.rb:11:in `call'
  actionpack (4.1.9) lib/action_dispatch/middleware/params_parser.rb:27:in `call'
  actionpack (4.1.9) lib/action_dispatch/middleware/flash.rb:254:in `call'
  rack (1.5.5) lib/rack/session/abstract/id.rb:225:in `context'
  rack (1.5.5) lib/rack/session/abstract/id.rb:220:in `call'
  actionpack (4.1.9) lib/action_dispatch/middleware/cookies.rb:562:in `call'
  activerecord (4.1.9) lib/active_record/query_cache.rb:36:in `call'
  activerecord (4.1.9) lib/active_record/connection_adapters/abstract/connection_pool.rb:621:in `call'
  activerecord (4.1.9) lib/active_record/migration.rb:380:in `call'
  actionpack (4.1.9) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
  activesupport (4.1.9) lib/active_support/callbacks.rb:82:in `run_callbacks'
  actionpack (4.1.9) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
  actionpack (4.1.9) lib/action_dispatch/middleware/reloader.rb:73:in `call'
  actionpack (4.1.9) lib/action_dispatch/middleware/remote_ip.rb:76:in `call'
  better_errors (2.1.1) lib/better_errors/middleware.rb:84:in `protected_app_call'
  better_errors (2.1.1) lib/better_errors/middleware.rb:79:in `better_errors_call'
  better_errors (2.1.1) lib/better_errors/middleware.rb:57:in `call'
  rack-contrib (1.2.0) lib/rack/contrib/response_headers.rb:17:in `call'
  meta_request (0.3.4) lib/meta_request/middlewares/headers.rb:16:in `call'
  actionpack (4.1.9) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
  actionpack (4.1.9) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
  railties (4.1.9) lib/rails/rack/logger.rb:38:in `call_app'
  railties (4.1.9) lib/rails/rack/logger.rb:20:in `block in call'
  activesupport (4.1.9) lib/active_support/tagged_logging.rb:68:in `block in tagged'
  activesupport (4.1.9) lib/active_support/tagged_logging.rb:26:in `tagged'
  activesupport (4.1.9) lib/active_support/tagged_logging.rb:68:in `tagged'
  railties (4.1.9) lib/rails/rack/logger.rb:20:in `call'
  quiet_assets (1.1.0) lib/quiet_assets.rb:27:in `call_with_quiet_assets'
  actionpack (4.1.9) lib/action_dispatch/middleware/request_id.rb:21:in `call'
  rack (1.5.5) lib/rack/methodoverride.rb:21:in `call'
  rack (1.5.5) lib/rack/runtime.rb:17:in `call'
  activesupport (4.1.9) lib/active_support/cache/strategy/local_cache_middleware.rb:26:in `call'
  rack (1.5.5) lib/rack/lock.rb:17:in `call'
  actionpack (4.1.9) lib/action_dispatch/middleware/static.rb:84:in `call'
  rack (1.5.5) lib/rack/sendfile.rb:112:in `call'
  railties (4.1.9) lib/rails/engine.rb:514:in `call'
  railties (4.1.9) lib/rails/application.rb:144:in `call'
  rack (1.5.5) lib/rack/lock.rb:17:in `call'
  rack (1.5.5) lib/rack/content_length.rb:14:in `call'
  rack (1.5.5) lib/rack/handler/webrick.rb:60:in `service'
  /Users/jimmiejackson/.rvm/rubies/ruby-2.3.3/lib/ruby/2.3.0/webrick/httpserver.rb:140:in `service'
  /Users/jimmiejackson/.rvm/rubies/ruby-2.3.3/lib/ruby/2.3.0/webrick/httpserver.rb:96:in `run'
  /Users/jimmiejackson/.rvm/rubies/ruby-2.3.3/lib/ruby/2.3.0/webrick/server.rb:296:in `block in start_thread'

Please let me know if there is any other code you might need to see. Thanks for your help, this is driving me crazy!


Solution

  • You have namespaced OmniauthCallbacksController under users as Users::OmniauthCallbacksController, make sure the controller path is your_app/app/controllers/users/omniauth_callbacks_controller‌​.rb i.e., it resides under users folder. Similarly, your devise routes should look something like:

    devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
    

    Note: users/omniauth_callbacks

    UPDATE

    Looking at the routes that you shared, you need to update routes for upgrade and setup as:

    devise_scope :user do
        get '/users/auth/:provider/upgrade' => 'users/omniauth_callbacks#upgrade', as: :user_omniauth_upgrade
        get '/users/auth/:provider/setup', :to => 'users/omniauth_callbacks#setup'
      end
    

    Again, note: users/omniauth_callbacks