Reputation: 2512
I've successfully implemented Devise with omniauth-facebook and am now trying my hand at Twitter. I've pretty much copied the Devise settings for Facebook into methods for Twitter. However, after successfully approving my app to use my Twitter account I'm redirected back to my user registration page (http://localhost:3000/users/sign_up). Why is this?
Console output
Started GET "/users/auth/twitter/callback?oauth_token=zeIyTgAAAAAAwAQEAAABVcusPxc&oauth_verifier=q24BAAziukc8bF6nnaxuRoouuGaPuoF3" for ::1 at 2016-07-08 14:01:51 -0400
I, [2016-07-08T14:01:51.984997 #44805] INFO -- omniauth: (twitter) Callback phase initiated.
Processing by Users::OmniauthCallbacksController#twitter as HTML
Parameters: {"oauth_token"=>"zeIyTgAAAAAAwAQEAAABVcusPxc", "oauth_verifier"=>"q24BAAziukc8bF6nnaxuRoouuGaPuoF3"}
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."provider" = $1 AND "users"."uid" = $2 ORDER BY "users"."id" ASC LIMIT 1 [["provider", "twitter"], ["uid", "248829852"]]
(0.2ms) BEGIN
(0.1ms) ROLLBACK
Redirected to http://localhost:3000/users/sign_up
Completed 302 Found in 165ms (ActiveRecord: 1.0ms)
controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController def facebook @user = User.from_omniauth(request.env["omniauth.auth"])
if @user.persisted?
sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated
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
def twitter
@user = User.from_omniauth(request.env["omniauth.auth"])
if @user.persisted?
sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated
set_flash_message(:notice, :success, :kind => "Twitter") if is_navigational_format?
else
session["devise.twitter_data"] = request.env["omniauth.auth"].except("extra")
redirect_to new_user_registration_url
end
end
def failure
redirect_to root_path
end
end
models/user.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable, :omniauth_providers => [:facebook, :twitter]
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
end
config/routes.rb
Rails.application.routes.draw do
devise_for :users,
:controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
root 'welcome#index'
end
Upvotes: 0
Views: 796
Reputation: 19
I was struggling with the same error, with Github authentication, and finally by adding scope to the config.omniauth
in devise.rb
, it worked! Maybe it needed scope user to retrieve email and other info
config.omniauth :github, ENV['GITHUB_APP_ID'], ENV['GITHUB_APP_SECRET'], scope: 'repo,user'
Upvotes: 0
Reputation: 5155
Add debug output to your twitter callback like this to see the exact error preventing transaction from committing:
def twitter
@user = User.from_omniauth(request.env["omniauth.auth"])
if @user.persisted?
sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated
set_flash_message(:notice, :success, :kind => "Twitter") if is_navigational_format?
else
session["devise.twitter_data"] = request.env["omniauth.auth"].except("extra")
puts @user.errors
redirect_to new_user_registration_url
end
end
Twitter is known to not require email during the registration so it may not return the value when doing oauth against such an account.
To the question in point, Devise provides automatic validations for some fields by default. From Devise source:
def self.included(base)
base.extend ClassMethods
assert_validations_api!(base)
base.class_eval do
validates_presence_of :email, if: :email_required?
To switch off the default email presence validation, put this in your User
model:
def email_required?
false
end
Depending on your use case you may also want to change the default authentication key to not use the email:
in config/initializers/devise.rb:
config.authentication_keys = [ :username ]
UPDATE
When using Devise-supplied generator, the user
table may end up with null: false
constraint on the email
field. To remove it, create a migration with:
change_column :users, :email, :string, :null => true
and update the database schema:
bundle exec rake db:migrate
Upvotes: 2