Search code examples
ruby-on-railsdeviseomniauthomniauth-facebook

NoMethodError undefined method `persisted?' for nil:NilClass when signing in with Facebook thru Omniauth/Devise?


I am putting the finishing touches on a Rails app, and everything was working fine just yesterday, (most of it still is). But now, when I try to sign in with Facebook I get the error NoMethodError undefined method persisted? for nil:NilClass I haven't changed any code in the omniauth_callbacks_controller, or in the User Model, so I do not understand why this is happening all of the sudden.

Here's the code in omniauth_callbacks_controller

def self.provides_callback_for(provider)
class_eval %Q{
  def #{provider}
    @user = User.from_omniauth(env["omniauth.auth"])

    if @user.persisted?
      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
}
end

[:twitter, :facebook].each do |provider|
provides_callback_for provider
end

And in User.rb

def self.from_omniauth(auth)
identity = Identity.where(provider: auth.provider, uid: auth.uid).first_or_create do |identity|
  if identity.user == nil
    user = User.new
    user.email = auth.info.email || "#{auth.uid}@#{auth.provider}.generated"
    user.password = Devise.friendly_token[0,20]
    user.provider = auth.provider
    if auth.provider == "facebook"
      user.name = auth.info.name
      user.username = "FacebookUser" + (1 + rand(1000)).to_s
    elsif auth.provider == "twitter"
      user.name = auth.info.name
      user.username = auth.info.nickname
    end
  end
  identity.user = user
end

identity.access_token = auth['credentials']['token']
identity.refresh_token = auth['credentials']['refresh_token']
identity.expires_at = auth['credentials']['expires_at']
identity.timezone = auth['info']['timezone']
identity.save
identity.user
end

I cannot figure out why it WAS working yesterday, but now it's not. Nothing has changed! I'm still accessing it from the same URL, I haven't messed with the API settings on Facebook, or in devise.rb.


Solution

  • the problem is that identity.user is nill. It could happen, because user not valid(not saved in db), in user model did not pass validations.
    I think problem can be in user.email = auth.info.email || "#{auth.uid}@#{auth.provider}.generated" - wrong email type. You can add something like puts user.errors in block wehe you created user.

    Also i don't understand why you need a model - identity. Much easier add field to user model

    Here is my code(it's work):

      def self.from_omniauth(auth)
        email = auth.info.email
        user = User.find_by(email: email) if email
        user ||= User.create do |user|
                  user.provider= auth.provider
                  user.uid= auth.uid
                  user.email = auth.info.email
                  user.password = Devise.friendly_token[0,20]
                  user.name = auth.info.name
                  user.email ||= "#{auth.uid}_#{auth.uid}@email.com"
                end
      end