Here is my controller
def social_login
user = User.from_omniauth(env["omniauth.auth"])
session_params = user.attributes.merge("email" => user.email, "password" => user.crypted_password)
#user_session ||= UserSession.new(session_params, true)
if #user_session.save
user = User.where(email: #user_session.email).first
redirect_to root_path, :notice => "Signed in succesfully from #{env["omniauth.auth"].provider.titleize}. Greetings #{user.name.titleize} ;)"
else
flash.now[:alert] = "Sign in failed."
render "new"
end
end
here is the model to handle the omniauth process
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.name
user.email = auth.info.email
user.password = auth.credentials.token
user.password_confirmation = auth.credentials.token
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.save!
end
end
I always getting error when trying to save the session. It says:
Authlogic::Session::Existence::SessionInvalidError: Your session is invalid and has the following errors: Email is not valid
can you guys help me? thanks
Did you enable the email permission in your facebook app config/rails's initializion?
Like this:
config.omniauth :facebook, "APP_ID", "APP_SECRET", {:scope => 'email,...'}
Related
I am starting with using omniauth with devise User model. Integration works well but a case is failing.
This is related code from omniauth callback controller:
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
before_action :find_user, only: [:facebook]
def facebook
process_omniauth_response('Facebook', request.env['omniauth.auth'], #user)
end
def failure
redirect_to root_path, flash: { error: 'Authentication \
failed, please try again!' }
end
private
def find_user
#user = User.from_omniauth(request.env['omniauth.auth'])
end
def process_omniauth_response(provider, env_data, user)
if user.persisted?
sign_in_and_redirect user, event: :authentication
set_flash_message(:notice, :success,
kind: provider) if is_navigational_format?
else
session["devise.#{provider.downcase}_data"] = env_data
redirect_to new_user_registration_url
end
end
end
And the User model methods:
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
info = auth.info
user.email = info.email
user.remote_profile_picture_url = info.image
user.name = info.name
user.password = Devise.friendly_token[0, 20]
end
end
def self.new_with_session(params, session)
super.tap do |user|
auth_data =
session['devise.facebook_data'] || session['devise.twitter_data']
fill_with_omniauth_data(user, auth_data) if auth_data
end
end
def self.fill_with_omniauth_data(user, auth_data)
data_info = auth_data['info']
user.email = data_info['email'] if user.email.blank?
user.name = data_info['name'] if user.name.blank?
...
end
So everything works fine i.e if a new user clicks on login by Facebook, after authentication by facebook he will come to signup page with pre-filled data but in case of this below case it is going to sign in page after omniauth callback action:
context 'when facebook email doesn\'t exist in the system' do
before(:each) do
stub_env_for_omniauth
get :facebook
end
it { response.should redirect_to new_user_registration_path }
it 'should create authentication with facebook id' do
authentication = User.where(provider: 'facebook', uid: '1234').first
puts authentication.inspect
authentication.should_not be_nil
end
end
And the stub method:
def stub_env_for_omniauth
request.env['devise.mapping'] = Devise.mappings[:user]
request.env['omniauth.auth'] = OmniAuth::AuthHash.new(
provider: 'facebook', uid: '1234', info: {
email: 'ghost#nobody.com', name: 'mock user'
},
extra: { raw_info: { age: 23 } }
)
end
I got this message:
Expected response to be a redirect to http://test.host/users/sign_up but was a redirect to http://test.host/users/sign_in
From debugging I got that user object is a new , not persisted when I check it in the 'find_user' method of controller but in case of spec it is a persisted one.
I would appreciate any help.
Thanks
I got some problem with OmniAuth FaceBook login into my webapp.
Tell me please, what should i edit to fix this error? Check the code.
Error in the browser:
undefined method `to_a' for "Name Surname":String
User.rb:
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
x = auth.info.name.to_a
user.name = x[0]
user.surname = x[1]
user.login = auth.info.uid
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
end
end
Omniauth_callback_controller.rb :
def facebook
if request.env["omniauth.auth"].info.email.blank?
redirect_to "/users/auth/facebook?auth_type=rerequest&scope=email"
end
#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"]
if(#user.surname.nil?)
redirect_to new_profile_path
else
redirect_to my_profile_path
end
end
end
devise.rb :
config.omniauth :facebook, '*********', '*********', {:client_options => {:ssl => {:verify => false}}}
name is a string and you are trying to convert it to array
x = auth.info.name.to_a
use split instead
x = auth.info.name.split
#=> ['Name', 'Surname']
You can make use of OmniAuth first_name and last_name:
Update your devise.rb:
config.omniauth :facebook, '*********', '*********', info_fields: 'email, first_name, last_name', {:client_options => {:ssl => {:verify => false}}}
and your user.rb:
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.name = auth.info.first_name
user.surname = auth.info.last_name
user.login = auth.info.uid
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
end
end
your user.rb should be like this
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
x = auth.info.name.split
if x.count > 1
user.name = x[0]
user.surname = x[1]
else
user.name = x[0]
end
user.login = auth.info.uid
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
end
end
But I would suggest to store in a single field, because name can be of more than two words so it would become difficult to identify name and surname.
this link should also help
I'm getting the error: "couldn't find user with id" when trying to sign in with facebook. I want it where if a user is had already been created it triggers the first set of code in the conditional and if the user is new it triggers the second set of code:
sessions_controller
def facebook
preexisting_user = User.find(params[:id]) # What should go in this line?
user = User.from_omniauth(env["omniauth.auth"])
if preexisting_user
cookies.permanent.signed[:user_id] = user.id
redirect_to root_url
flash.now[:info] = 'Welcome Back to Live to Challenge!'
else
action = session.delete(:challenge_action)
user.challenges.create(action: action)
user.send_welcome_email
user.remember
cookies.permanent.signed[:user_id] = user.id
redirect_to tutorial_url
flash.now[:info] = 'Welcome to Live to Challenge!'
end
end
user.rb
def self.from_omniauth(auth)
# Sets 60 day auth token
oauth = Koala::Facebook::OAuth.new("154037ewr2976229929", "ee917abf2ere8f1c98274cdfwqreaebb1346f4")
new_access_info = oauth.exchange_access_token_info auth.credentials.token
new_access_token = new_access_info["access_token"]
new_access_expires_at = DateTime.now + new_access_info["expires"].to_i.seconds
where(provider: auth.provider, uid: auth.uid).first_or_initialize.tap do |user|
user.provider = auth.provider
user.image = auth.info.image
user.uid = auth.uid
user.name = auth.info.name
user.oauth_token = new_access_token # auth.credentials.token <- your old token. Not needed anymore.
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.password = (0...8).map { (65 + rand(26)).chr }.join
user.email = SecureRandom.hex + "#mailinator.com" unless user.email.present?
user.activated = true
user.save!
end
end
You can try below code, i am sure it will work.
def facebook
user = User.from_omniauth(env["omniauth.auth"])
# preexisting_user = User.find(params[:id]) # What should go in this line?
# user.persisted? is what you need to add if you want to add here
# if user pre existed, it will execute if block otherwise else block.
# checks if pre-existing user
if user.persisted?
cookies.permanent.signed[:user_id] = user.id
redirect_to root_url
flash.now[:info] = 'Welcome Back to Live to Challenge!'
else
action = session.delete(:challenge_action)
user.challenges.create(action: action)
user.send_welcome_email
user.remember
cookies.permanent.signed[:user_id] = user.id
redirect_to tutorial_url
flash.now[:info] = 'Welcome to Live to Challenge!'
end
end
On My current app that i'm developing, i can sign up using Facebook and Google+. But when I added the ability for signing up with just a regular email, i got this error, I'll appreciate some help please ...
Here are some of my code
#SessionsController
def create
#user = User.from_omniauth(env["omniauth.auth"])
# session[:user_id] = #user.id
# redirect_to root_path
#user = User.find_by_email params[:email]
if #user && #user.authenticate(params[:password])
session[:user_id] = #user.id
redirect_to root_path
else
flash[:alert] = "Wrong email or password"
render :new
end
end
#user.rb
class User < ActiveRecord::Base
has_secure_password
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.name
user.email = auth.info.email
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.image = auth.info.image
user.gender = auth.extra.raw_info.gender
user.location = auth.extra.raw_info.location.name
user.location = auth.extra.raw_info.locale
# user.url = auth_hash['info']['urls'][user.provider.capitalize]
user.save
end
end
So When attempting to signUp with using the email, here's what happen !
enter image description here
I'm guessing that error coming because i'm calling from_omniauth and i'm not passing a provider, which i don't need to use in this case.
You might consider starting fresh - using https://github.com/plataformatec/devise and then adding OmniAuth on top of this (https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview).
How to use ActiveRecord::Base.transaction after first_or_create ?
here is my model method:
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.name
user.email = auth.info.email
user.password = 'password'
user.password_confirmation = 'password'
user.crypted_password = 'password'
user.oauth_token = auth.credentials.token
user.oauth_expires_at = Time.at(auth.credentials.expires_at)
user.save!
end
end
In my controller:
def social_login
#user = User.from_omniauth(env["omniauth.auth"])
ActiveRecord::Base.transaction do
add_sites(#user)
#user.mobile = mobile_view?
#user.addresses.last.email = #user.email
add_point_to_customer(#user)
#user.add_mail_subscription_if_doesnt_exist(active_site)
end
end