Search code examples
ruby-on-railsomniauth-facebook

uninitialized constant Users for omniauth_callbacks_controller with gem omniauth-facebook in ruby on rails app


I am having trouble with devise and omniauth-facebook with rails. I installed gem omniauth-facebook and gem devise.

I have set my fb secret and keys in config/application.yml. I configured devise in # config/initializers/devise.rb :

Devise.setup do |config|
  config.omniauth :facebook, ENV["FB_ID"], ENV["FB_SECRET"], scope: 'email', info_fields: 'email, first_name,last_name', image_size: 'large'
end

I modified my routes as follow :

config/routes.rb

Rails.application.routes.draw do
  devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
end

I changed my user model :

# app/models/user.rb

class User < ActiveRecord::Base
  devise :omniauthable, omniauth_providers: [:facebook]
end

I added the following rails migration :

$ rails g migration AddOmniauthToUsers \
    provider uid picture first_name last_name token token_expiry:datetime
$ rake db:migrate

In my User model :

# app/models/user.rb
class User < ActiveRecord::Base
  def self.find_for_facebook_oauth(auth)
    where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
      user.provider = auth.provider
      user.uid = auth.uid
      user.email = auth.info.email
      user.password = Devise.friendly_token[0,20]  # Fake password for validation
      user.first_name = auth.info.first_name
      user.last_name = auth.info.last_name
      user.picture = auth.info.image
      user.token = auth.credentials.token
      user.token_expiry = Time.at(auth.credentials.expires_at)
    end
  end
end

I created a new controller to handle Omniauth callback request

# app/controllers/users/omniauth_callbacks_controller.rb

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def facebook
    user = User.find_for_facebook_oauth(request.env['omniauth.auth'])

    if user.persisted?
      sign_in_and_redirect user, event: :authentication
      set_flash_message(:notice, :success, kind: 'Facebook') if is_navigational_format?
    else
      session['devise.facebook_data'] = request.env['omniauth.auth']
      redirect_to new_user_registration_url
    end
  end
end

My facebook connect works on my local app but it makes the app crash on heroku from the start with this error message:

I have correctly set my environment variables on heroku and heroku run rake db:migrate.

Where does this error comes from and how can I fix it ?

/app/app/controllers/Users/omniauth_callbacks_controller.rb:1:in `<top (required)>': uninitialized constant Users (NameError)
    from /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/engine.rb:472:in `block (2 levels) in eager_load!'
    from /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/engine.rb:471:in `each'
    from /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/engine.rb:471:in `block in eager_load!'
    from /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/engine.rb:469:in `each'
    from /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/engine.rb:469:in `eager_load!'
    from /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/engine.rb:346:in `eager_load!'
    from /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/application/finisher.rb:56:in `each'
    from /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/application/finisher.rb:56:in `block in <module:Finisher>'
    from /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/initializable.rb:30:in `instance_exec'
    from /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/initializable.rb:30:in `run'
    from /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/initializable.rb:55:in `block in run_initializers'
    from /app/vendor/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:228:in `block in tsort_each'
    from /app/vendor/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
    from /app/vendor/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:431:in `each_strongly_connected_component_from'
    from /app/vendor/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:349:in `block in each_strongly_connected_component'
    from /app/vendor/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:347:in `each'
    from /app/vendor/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:347:in `call'
    from /app/vendor/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:347:in `each_strongly_connected_component'
    from /app/vendor/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:226:in `tsort_each'
    from /app/vendor/ruby-2.3.1/lib/ruby/2.3.0/tsort.rb:205:in `tsort_each'
    from /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/initializable.rb:54:in `run_initializers'
    from /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/application.rb:352:in `initialize!'
    from /app/config/environment.rb:5:in `<top (required)>'
    from /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/application.rb:328:in `require_environment!'
    from /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/commands/commands_tasks.rb:142:in `require_application_and_environment!'
    from /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/commands/commands_tasks.rb:67:in `console'
    from /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
    from /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.6/lib/rails/commands.rb:17:in `<top (required)>'
    from /app/bin/rails:9:in `require'
    from /app/bin/rails:9:in `<main>'

Solution

  • 1st possible solution:

    The name error uninitialized constant class will occur if your rails console is not loaded with configuration of the class file containing method being called. It means that the class was just not loaded with the application.

    Do you see this config.autoload_paths += %W(#{config.root}/lib) in your application.rb file? if not can you put it there and try again? let me know how it goes.

    2nd possible solution:

    try to switch back to:

     devise_for :users, controllers: { omniauth_callbacks: 'omniauth_callbacks' 
    

    and of course move the chnaged

    class OmniauthCallbacksController < Devise::OmniauthCallbacksController
    

    to app/controllers/omniauth_callbacks_controller.rb

    hope this helps! let me know