Skip email validation for omniauth-twitter on devise 2.0 - ruby-on-rails

I'm using devise 2.0 and gem omniauth-twitter
The problem is that twitter does not send an email in response, so the model user of my application validates that there is an email and I get the following error in the callback:
Email can't be blank
I have this in my user.rb model:
#config omniauth twitter
def self.find_for_twitter_oauth(access_token, signed_in_resource = nil)
data = access_token.extra.raw_info
if user = User.where(:username => data.screen_name).first
user
else
User.create!(:username => data.screen_name, :password => Devise.friendly_token)
end
end
and I have this in my omniauth_callbacks_controller.rb
def twitter
#user = User.find_for_twitter_oauth(request.env["omniauth.auth"], current_user)
if #user.persisted?
flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Twitter"
sign_in_and_redirect #user, :event => :authentication
else
# http://stackoverflow.com/questions/7117200/devise-for-twitter-cookie-overflow-error
session["devise.twitter_data"] = request.env["omniauth.auth"].except('extra')
redirect_to new_user_registration_url
end
end
I want force to user to give a email address for send newsletter, advertirser...etc
How can I fix this problem?
Thank you!

Add this to your User model:
def email_required?
super && provider.blank?
end
You can use an equivalent method for the password:
def password_required?
super && provider.blank?
end
This should override the field requirements when using Omniauth providers.

I am facing the same problem, Twitter doesn't give you the email via oauth, you have to think in another way to obtain the email. The only solution that I figured out, is override the callback and use the twitter data to autocomplete a form and give the user the chance to complete his mail by himself and then sign up and save the user in the database.
Look the following question:
Is there a way to get an user's email ID after verifying his/her Twitter identity using OAuth?

A solution is explained thoroughly here:
http://asciicasts.com/episodes/236-omniauth-part-2
And on GitHub:
https://github.com/fertapric/rails3-mongoid-devise-omniauth/wiki/How-To:-Retrieve-email-information-(middle-step)-from-providers-like-Twitter-or-LinkedIn
For some reason, this question shows up higher in Google's ranks than these links, so I thought I'd add them to the answers.

You need to remove the presence validation of the email field.
Follow this post and see if that works.
Sorry for the late response, hope this helps.

Related

Omniauth Callback

Im using devise with my rails 4 app. I authenticate with Facebook, LinkedIn and email.
I've just started to use Figaro and the only change I have made to my code is to swap the password that I use for my email account out of the production.rb into my application.yml file.
Now, when I test the LinkedIn registration link, I get an error saying that something went wrong (after pressing "Register with LinkedIn"). I get the same error when I try to authenticate with the other options.
I have a callback error in my omniauth callback controller for linkedin. The line with the problem is the '#user.send_admin_email' below:
def linkedin
#user = User.find_for_linkedin_oauth(request.env["omniauth.auth"])
if #user.persisted?
#user.send_admin_mail
redirect_to root_path, :event => :authentication
# sign_in_and_redirect #user, :event => :authentication #this will throw if #user is not activated
# set_flash_message(:notice, :success, :kind => "LinkedIn") if is_navigational_format?
else
session["devise.linkedin_data"] = request.env["omniauth.auth"]
redirect_to root_path
end
end
I have a mailer set up which sends me an email to tell me when there is a new registration. It uses the email address for which I moved the password from production.rb to application.yml
Does anyone know how to resolve this error?
Thank you very much
It is possible that the problem is the text-encoding of your application.yml file, especially if your email password has non-standard characters in it. Try firing up the console, and just output your password as it looks with to_s
p ENV['your_figaro_key'].to_s
See if this returns what you would expect
Hmm, it seems a "strong parameter" problem to me. Check your "send_admin_mail" to see if there is a "update_atributes" (or a "save").
My guess is that your user.rb is something like:
class User < ActiveRecord::Base
...
attr_accessor :extras
def self.find_for_linkedin_oauth(access_token, signed_in_resource=nil)
...
user = User.where(...)
...
user.extras = access_token.extras
...
end
def send_admin_mail
...
self.update_attributes(some_attribute: extras["some_attribute"])
...
end
If you are doing this, "save" will try to do an UPDATE with a non-permitted parameter. The correct version must be something this:
self.update_attributes(some_attribute: extras.permit(:some_attribute))
If I'm not wrong, the first implementation worked in the previous versions of strong parameters, but not anymore.

I keep getting "Not found. Authentication passthru" for Facebook connect login with Devise - Need debug advice

I've seen a couple people ask a similar question, but I really need advice on how to debug this issue. I'm trying to setup facebook connect using Devise using the article here: https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview
Every time I click on the login with facebook link, I get the blank page that just says: Not found. Authentication passthru. Clearly, there is no JavaScript/ajax setup on the prior page to pull up the facebook login screen.
I know this can work on my system, as I made a blank project with the exact same code from the link above and it works. Of course, my project is much bigger with lots of code, so I'm trying to figure out what in my project is causing this not to fire.
Any help on how to debug is appreciated.
Thanks!
This is the #passthru code from the devise source.
def passthru
render :status => 404, :text => "Not found. Authentication passthru."
end
Which means that devise is unable to recognize your facebook callback. Make sure you setup up your callback controller properly or post your user controller code.
I ran into the same error. I was missing the Facebook callback controller (app/controllers/users/omniauth_callbacks_controller.rb):
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
# ...
def facebook
respond_to do |format|
format.html {
#user = User.find_for_facebook(request.env["omniauth.auth"])
if #user.persisted?
sign_in_and_redirect #user
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
end
This code references the method "find_for_facebook" in my user model (app/models/user.rb):
class User < ActiveRecord::Base
# ...
def self.find_for_facebook(auth_hash)
user = User.where(:email => auth_hash.info["email"]).first
unless user
user = User.create(
username: auth_hash.info["nickname"],
email: auth_hash.info["email"],
password: Devise.friendly_token[0,20])
end
user.provider = auth_hash["provider"]
user.uid = auth_hash["uid"]
user
end
end
Make sure to restart your development server so all the changes get picked up.

"omniauth-twitter" email id is not fetched from twitter in ruby on rails

i am using omniauth-twitter gem to enable Twitter login in my rails application. Here is my code ...
gemfile -
gem 'omniauth', '~> 1.1.1'
gem 'omniauth-twitter'
routes.rb -
match '/auth/twitter/callback', to: 'users#twitter_login'
match 'auth/failure', to: 'static_pages#home'
User_controller.rb -
def twitter_login
auth = request.env['omniauth.auth']
authentication = Authentication.find_by_provider_and_uid(auth['provider'],auth['uid'])
if authentication
sign_in authentication.user
redirect_to root_url
else
if(User.where(:email => auth['extra']['raw_info']['email']).exists?)
flash[:notice] = "You already have account in ibetter"
redirect_to root_url
else
user = User.new
user.apply_omniauth(auth)
if user.save(:validate => false)
sign_in user
flash[:notice] = "Welcome to Ginfy"
redirect_to root_url
else
flash[:error] = "Error while creating a user account. Please try again."
redirect_to root_url
end
end
end
end
session_helper.rb -
def sign_in(user)
cookies.permanent[:remember_token] = user.remember_token
self.current_user = user
end
User.rb model -
before_save { |user| user.email = email.downcase }
def apply_omniauth(auth)
self.email = auth['extra']['raw_info']['email']
self.name = auth['extra']['raw_info']['name']
authentications.build(:provider => auth['provider'], :uid => auth['uid'], :token => auth['credentials']['token'])
end
erb code -
<%= link_to image_tag("login-twitter.png", alt: "twitter"), "/auth/twitter",:class => "popup", :"data-width" => "600", :"data-height" => "400" %>
Email id is not fetched from twitter. Please help
Twitter doesn´t give you the email via API.
This works if you are using omniauth-facebook gem for example, but twitter doesn´t offer you the email - you have to create a workaround.
For example ask the user in a second step to fill in his/her email address.
The accepted answer is outdated. Twitter is providing email now via this Special Permission Form. Complete the form requesting special permissions and wait for approval.
Also you can see this answer for more info.
Omniauth gem fetch the users email
see: include_email=true
you have to enable the additional information
The GEM is working fine the problem is Twitter do not return email for some reason. unlike facebook..
As stated in the answer from Avinash kumar singh, editing the Twitter App additional permissions to request an email address:
Accordingly, a request for email is added to the authorization dialog:
This will result in a value being present for auth.info.email in the response hash.
Note: I am using the omniauth-twitter gem.

sign_in_and_redirect with omniauth-facebook to specific language

I'm using omniauth-facebook gem with rails 3.2 and devise 2.0.
I have a website with 2 languages, english and spanish.
http://localhost:3000/en
http://localhost:3000/es
The gem works fine for english users because in omniauth_callbacks_controller.rb the redirect go to http://localhost:3000/en
This is my omniauth_callbacks_controller.rb for facebook:
def facebook
#user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)
if #user.persisted?
flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Facebook"
sign_in_and_redirect #user, :event => :authentication
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
Then problem is for spanish users. that if they use http://localhost:3000/es the redirect from callback go to http://localhost:3000/en
I want that redirect from callback go to specific language that is using that user.
How can I do it?
Thank you!
I had similar issue, and did not find a way to change the callback url, but I could set the locale in the method when the callback happens.
The original url (which has the orignal correct locale) is in stored in request.env['omniauth.origin']
So in facebook method pick the locale from the original url, where it is in similar way the two letters after the domain part.
I added in the beginning of the facebook method:
I18n.locale = exctract_locale_from_url(request.env['omniauth.origin']) if request.env['omniauth.origin']
Where the exctract_locale_from_url is a horrible looking regexp :)
def exctract_locale_from_url(url)
url[/^([^\/]*\/\/)?[^\/]+\/(\w{2})(\/.*)?/,2]
end
I think you must extract your omniauth config to yaml file and insert "#{i18n.locale}" to the end of callback link.

Integrating Devise with Twitter

I am currently using this guide to try to integrate twitter into Devise.
It is a little challenging because twitter's OAuth does not provide email addresses. Hence the flow of the sign up should be:
User clicks "Sign in with twitter"
Oauth call back to twitter's callback
Ask for the user for email (I need that for my site)
Sign in user.
I realized that if the user already has an account on my system with Twitter, I must be able to find the account. Hence I have added 2 extra field to the user model: oauth_provider, oauth_uid.
In omniauth_callbacks_controller:
def twitter
#user = User.find_for_twitter_oauth(env["omniauth.auth"], current_user)
if #user.persisted?
flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Twitter"
sign_in_and_redirect #user, :event => :authentication
else
flash[:warn] = "We still need a little more info!"
redirect_to new_user_registration_url
end
end
In user.rb
# The trick here is that twitter does not give you an email back
# So we should make use of uid and provider
def self.find_for_twitter_oauth(oauth_hash, signed_in_resource=nil)
uid = oauth_hash['uid']
if user = User.find_by_oauth_provider_and_oauth_uid('twitter', uid)
user
else
User.create(:password => Devise.friendly_token[0,20],
:oauth_provider => "twitter",
:oauth_uid => oauth_hash['uid'])
end
end
However, I have debugged this thoroughly and realized that if I redirect a user to new_registration_url, the User created in user.rb will be wiped.
How can I do the following:
If user cannot be found via oauth_provider and oauth_uid, create a User object with these credentials
direct user to new_registration_url
When the user have submitted his/her email, create the user with the same user object created in 1)
I have tried using session, but it gets really messy as I have to monkey patch devise's new and create for registrationscontroller.rb.
Please someone provide me a way to do this.
I have not been successful yet. Let me show you what I have written.
I followed these 2 screencasts and it is exactly what you want.
You can try it out! He is using the omniauth gem, which is very easy and awesome :-)
http://railscasts.com/episodes/235-omniauth-part-1
http://railscasts.com/episodes/236-omniauth-part-2

Resources