undefined local variable or method `user' omniauth callbacks controller

1.7k views Asked by At

I'm trying to implement facebook login authentication using devise and omniauth, but I got an error during the callback section.

The error goes like this...

> `User Load (0.3ms)  SELECT  "users".* FROM "users" WHERE "users"."provider" = ? AND "users"."uid" = ?  ORDER BY "users"."id" ASC LIMIT 1  [["provider", "facebook"], ["uid", "1517802078458724"]]
   (0.1ms)  begin transaction
   (0.1ms)  rollback transaction
Completed 500 Internal Server Error in 411ms

NameError (undefined local variable or method `user' for #<User:0x007f3008b8a760>):
  app/models/user.rb:34:in `password_required?'
  app/models/user.rb:18:in `block in from_omniauth'
  app/models/user.rb:12:in `tap'
  app/models/user.rb:12:in `from_omniauth'
  app/controllers/omniauth_callbacks_controller.rb:4:in `all'`

It seems like things work until /auth/facebook/ and then it goes up to the part where retrieving uid and provider ends.

My code in controllers, model and routes are as follows..

For callbacks controller and application controller

  class OmniauthCallbacksController < Devise::OmniauthCallbacksController

  def all
    user = User.from_omniauth(request.env["omniauth.auth"])
    if user.persisted?
      sign_in_and_redirect user, notice: "Signed in!"
    else
      session["devise.user_attributes"] = user.attributes
      redirect_to new_user_registration_url
    end
  end
  alias_method :facebook, :all
end


class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

end

My user.rb model

class User < ActiveRecord::Base
  has_many :authentications
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable, :omniauthable,
         :recoverable, :rememberable, :trackable, :validatable,
         :omniauth_providers => [:facebook]

  attr_accessible :email, :password, :password_confirmation

  def self.from_omniauth(auth)
    where(provider: auth.provider, uid: auth.uid).first_or_initialize.tap do |user|
      user.provider = auth.provider
      user.uid = auth.uid
      user.name = auth.info.name
      user.oauth_token = auth.credentials.token
      user.oauth_expires_at = Time.at(auth.credentials.expires_at)
      user.save!
    end
  end

  def self.new_with_sessions(params, session)
    if session["devise.user_attributes"]
      new(session["devise.user_attributes"], without_protection: true ) do |user|
        user.attributes = params
        user.valid?
      end
    else
      super
    end
  end

  def password_required?
    super && user.blank?

  end
end

My schema.rb

ActiveRecord::Schema.define(version: 20141120211712) do

create_table "users", force: true do |t|
    t.string   "email",                  default: "", null: false
    t.string   "encrypted_password",     default: "", null: false
    t.string   "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.integer  "sign_in_count",          default: 0,  null: false
    t.datetime "current_sign_in_at"
    t.datetime "last_sign_in_at"
    t.string   "current_sign_in_ip"
    t.string   "last_sign_in_ip"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string   "provider"
    t.string   "uid"
    t.string   "name"
    t.string   "oauth_token"
    t.datetime "oauth_expires_at"
  end

  add_index "users", ["email"], name: "index_users_on_email", unique: true
  add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true

end

My routes.rb

Rails.application.routes.draw do

  devise_for :users, :controllers => { :omniauth_callbacks => "omniauth_callbacks" } 
  root            'static_pages#home'
  get 'help' =>   'static_pages#help'
  get 'about' =>  'static_pages#about'
  get 'contact' => 'static_pages#contact'

and finally my gemfile

source 'https://rubygems.org'
ruby   '2.1.4'

gem 'rails',                   '4.2.0.beta4'
gem 'bcrypt',                  '3.1.7'
gem 'faker',                   '1.4.2'
gem 'carrierwave',             '0.10.0'
gem 'mini_magick',             '3.8.0'
gem 'fog',                     '1.23.0'
gem 'will_paginate',           '3.0.7'
gem 'bootstrap-will_paginate', '0.0.10'
gem 'bootstrap-sass',          '3.2.0.0'
gem 'sass-rails',              '5.0.0.beta1'
gem 'uglifier',                '2.5.3'
gem 'coffee-rails',            '4.0.1'
gem 'jquery-rails',            '4.0.0.beta2'
gem 'turbolinks',              '2.3.0'
gem 'jbuilder',                '2.2.3'
gem 'rails-html-sanitizer',    '1.0.1'
gem 'sdoc',                    '0.4.0', group: :doc
gem 'devise', github: 'plataformatec/devise'
gem 'omniauth'
gem 'omniauth-twitter'
gem 'omniauth-facebook'
gem 'omniauth-linkedin'
gem 'figaro'
gem 'protected_attributes'

I would really like this feature of facebook login in my app... Thank you very much in advance. I would greatly appreciate any input..

2

There are 2 answers

1
Zero Fiber On BEST ANSWER

The problem is in the password_required? which is called when the user is saved.

def password_required?
  super && user.blank?

end

Its trying to test whether the user is blank? However the user variable/method does not exist in its scope. Instead you need to use self which refers to the current instance of User.

So the line should be:

super && self.blank?

or just:

super && blank?
0
ahk On

I was able to solve this problem throughmaking

def password_required?
  super && user.blank?

end

into

super && self.blank?

and I also added

user.email = auth.info.email

to the self.from_omniauth(auth) section. Thanks guys