0

I use the gem 'omniauth-twitter' to let my user login to my app. Then I can use their name and profile image from twitter on my app.

The problem I am facing is that when a user update its name or image on twitter, it doesn't update on my app.

Here is my config:

app/controllers/omniauth_callbacks_controller.rb

class OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def all
    user = User.from_omniauth(request.env["omniauth.auth"])

    if user.persisted?
      flash.notice = "Signed in!"
      sign_in_and_redirect user     
    else
      session["devise.user_attributes"] = user.attributes
      redirect_to new_user_registration_url
    end

  end

  alias_method :twitter, :all
end

app/models/user.rb

  def self.from_omniauth(auth)
    where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
      user.provider = auth.provider
      user.uid = auth.uid
      user.name = auth.info.nickname
      user.image = auth["info"]["image"].sub("_normal", "")
    end
  end

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

end

I did not suceed to update user attributes. Any ideas following my configuration to do this ? thanks.

  • So, your issue is: a) login on your app with twitter; b) go to twitter and change image; c) login again on your app; d) expect to see new image but see old one ? (and the same for the name?) – Samuel Brandão Jan 21 '16 at 11:31

1 Answers1

1

I believe you may be mistaken about the semantics of #first_or_create. The correct semantics is:

A) try finding a record with the provided query scope (your where clause -> provider: auth.provider, uid: auth.uid)

B.1) If found any, return the first one not executing the passed in block.

B.2) If not found any, initialize a new one and pass it to the block passed as argument (which in your case is what sets the name and image)

So, on the first login, the program flow follows A > B.2, which creates a new user with the correct name and image. On the successive logins, it follows A > B.1, which just return the user already on the database.

You can solve this issue ensuring the code that sets name and picture always runs:

def self.from_omniauth(auth)
  user = find_or_initialize_by(provider: auth.provider, uid: auth.uid)
  user.name  = auth.info.nickname
  user.image = auth["info"]["image"].sub("_normal", "")

  user.save
  user
end

Cheers!

Samuel Brandão
  • 376
  • 2
  • 4
  • Samuel, thank your for your clear explanation of my problem. You were right. The model was checking for user information as it was when the user SIGNED up. – Jérémy Zaccherini Jan 21 '16 at 17:52