Adam Rogers
Posted on January 3, 2020
There are a number of tutorials, including the omniauth overview, that suggest having a method along the following lines:
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.email = auth.info.email
user.password = Devise.friendly_token[0, 20]
user.name = auth.info.name # assuming the user model has a name
user.image = auth.info.image # assuming the user model has an image
end
end
That first_or_create
will try to find a user by the auth.provider
(e.g. twitter
) and auth.uid
(e.g. rodreegez
) and create one with those attributes if one isn't found. What it doesn't do is update a found user if the user is found.
So, in the example above if, when an existing user signs in with Twitter having updated their name, our app won't get the new name of the user.
Instead, we should do something like this to ensure we are updating our user information when the user logs in:
def self.from_omniauth(auth)
user = find_or_initialize_by(provider: auth.provider, uid: auth.uid)
user.email = auth.info.email
user.password = Devise.friendly_token[0, 20]
user.name = auth.info.name # assuming the user model has a name
user.image = auth.info.image # assuming the user model has an image
user.save
user
end
That find_or_initialize_by
behaves more like we expect it in this situation. Or at least, it behaves in a way that is more appropriate to the task we have at hand - it either finds an existing record or initializes a new one, but doesn't try to save the record. We are then able to set the attributes of the found-or-initialized user, save it, and return the saved-or-updated user to the caller.
Hope that helps.
🍻
Posted on January 3, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.