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!
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