The first time the User is created but it doesn't keep me logged in, even if I set sign_in #user after creating the Customer, the next time I access it does sign me in.
Am I missing something?
class CallbacksController < Devise::OmniauthCallbacksController
def facebook
#user = User.from_omniauth(request.env["omniauth.auth"])
if resource.id.blank?
sign_in resource, event: :authentication
set_flash_message(:notice, :success, kind: 'Facebook') if is_navigational_format?
# Create customer
Customer.create(:user_id => resource.id, :name => resource.name, :lastname => resource.lastname)
redirect_to new_user_session_path
else
sign_in resource_name, resource
redirect_to profile_path
end
end
end
So I had to add
session["warden.user.user.key"][0] = resource.id
for a weird reason it wasn't adding the ID from the user to the session.
This worked for me but I don't think is the "way" to do it.
Related
I'm using Rails 6 + Devise for login/registration. Users can register/login with Facebook via omniauth.
I want to log one analytics event when the user logs in, and a different analytics event when they register for the first time.
app/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
set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
flash[:log_event] = {
'event_category' => 'engagement',
'event_name' => 'login',
'method' => 'facebook'
}
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
def failure
redirect_to root_path
end
end
The flash[:log_event] is passed to Google Analytics. My problem is that Devise seems to follow the same code path for first registration as it does for a regular login.
I suppose I could check the #user.created_at timestamp, and treat it as a registration if it's a couple of minutes old, but I'm sure there's a cleaner solution.
You can always make your own version of User.from_omniauth. Notice the first_or_initialize instead of ..._create
# in app/models/user.rb
def self.from_omniauth(auth)
user = where(auth.slice(:provider, :uid)).first_or_initialize do |new_user|
new_user.provider = auth.provider
new_user.uid = auth.uid
new_user.username = auth.info.nickname
end
user.image_url = auth.info.image # need to update in case image changed on provider's site
user
end
Then in your controller check for new_record?
#user = User.from_omniauth(request.env["omniauth.auth"])
if #user.new_record?
#user.save # Important step I missed earlier
# ... Do some custom thing here for your app
end
if #user.persisted?
# ....
I am integrating facebook login in my application using the example code from the Omniauth documentation
https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview
def self.from_omniauth(hash)
where(email: hash.info.email).first_or_create do |user|
user.email = hash.info.email
user.password = Devise.friendly_token[0,20]
user.username = hash.info.name # assuming the user model has a name
end
end
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
# render :text => request.env['omniauth.auth'].to_yaml
# You need to implement the method below in your model (e.g. app/models/user.rb)
#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
end
I followed the example as it is. However as the code in omniauth_callbacks_controller I'd say if an user is a new to the application then it should follow the else statement and be redirected to user registration url. However what happens is that a new user is created in the database always. Shouldn't I fall in the else statement in case the user has no account yet in my app?
According to the suggested implementation of the method from_omniauth I understand that first_or_create actually creates a new user in the db using the information from facebook. But if that's the case, what is the use of the else option redirecting to new_user_registration_url?
Anything I am not seeing?
I'm using devise with my Rails 4 app.
I have the following in my user.rb model:
def send_admin_mail
AdminMailer.new_user_waiting_for_approval(self).deliver
end
def send_user_welcome_mail
AdminMailer.new_user_waiting_for_access(user).deliver
end
The first method sends me an email when a new user registers. The aim is for the second method to send a welcome email to the new user. The first method works. The second raises an issue with 'no_method_error' (undefined method email in my callbacks controller).
My callback controller has the following:
def linkedin
#user = User.find_for_linkedin_oauth(request.env["omniauth.auth"])
if #user.persisted?
#user.send_admin_mail
#user.send_user_welcome_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
My admin_mailer has:
def new_user_waiting_for_approval(user)
#user = user
mail(to: "myemailaddress#gmail.com", from: "myemailaddress#gmail.com",
subject: "Registration Request #{user.first_name} #{user.last_name} <#{user.email}>")
end
def new_user_waiting_for_access(user)
#user = user
mail(to: user.email, from: "myemailaddress#gmail.com", subject: "Welcome to Co #{user.first_name}")
end
I'm wondering whether I need to replace user with current_user to make use of the devise method or maybe whether some variation on {} and/or "" is required around the user.email in the second method?? I've tried a few different variations and combinations but haven't had any success.
Thank you for your help.
def send_user_welcome_mail
AdminMailer.new_user_waiting_for_access(user).deliver
end
should be replaced with
def send_user_welcome_mail
AdminMailer.new_user_waiting_for_access(self).deliver
end
user -> self
I am working on a rails app right now that allows user's to log in normally, via twitter, and via Facebook as well. I am using devise, omniauth-twitter, and omniauth-facebook.
After signing up/registering, I want to redirect users to the page verify_user_email_path. I have my custom devise RegistrationsController which overrides the standard devise RegistrationsController. It looks like this:
class CustomDeviseControllers::RegistrationsController < Devise::RegistrationsController
def verify_email
flash[:notice] = ""
end
def update_email
#user = User.find(current_user.id)
params[:user].delete(:current_password)
if #user.update_without_password(devise_parameter_sanitizer.sanitize(:account_update))
flash[:notice] = "Welcome! You have signed up successfully."
sign_in #user, :bypass => true
redirect_to bookshelf_index_url
else
#error_message = "You have entered an invalid email address"
render "verify_email"
end
end
protected
def after_sign_up_path_for(resource)
# I WANT TO REDIRECT USERS HERE AFTER SIGNING UP
verify_user_email_path
end
end
As you can see, after any user signs up, they should be redirected to verify_user_email_path. However/sadly, users are only redirected if they sign up normally. So when users register on my site (they enter in an email, a password, and then confirm their password), after_sign_up_path_for correctly redirects users to verify_user_email_path. If users sign up via Facebook/Twitter, the users are simply redirected to the root_url instead. That is the bug I need to fix.
This is my custom OmniauthCallbacksController (underneath the all caps comment is where I sign users in):
class CustomDeviseControllers::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def self.provides_callback_for(provider)
class_eval %Q{
def #{provider}
#user = User.from_omniauth(request.env["omniauth.auth"])
if #user.persisted?
# HERE IS WHERE I SIGN USERS IN
sign_in_and_redirect #user, event: :authentication
set_flash_message(:notice, :success, kind: "#{provider}".capitalize) if is_navigational_format?
else
session["devise.#{provider}_data"] = env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
}
end
[:twitter, :facebook].each do |provider|
provides_callback_for provider
end
end
Aaaand here, is my config/routes.rb:
Rails.application.routes.draw do
devise_for :users, :controllers => {
omniauth_callbacks: 'custom_devise_controllers/omniauth_callbacks',
registrations: 'custom_devise_controllers/registrations' }
devise_scope :user do
get "users/verify_email" => 'custom_devise_controllers/registrations#verify_email', :as => :verify_user_email
post "users/update_email" => 'custom_devise_controllers/registrations#update_email', :as => :update_user_email
end
Instead of using after_sign_up_path_for in my Registrations controller, I use after_sign_in_path_for in the application controller. If the number of sign in attempts equals one, that means the user just signed up.
Here is my application_controller.rb:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
def after_sign_in_path_for(resource)
if resource.sign_in_count == 1
verify_user_email_path
else
root_url
end
end
end
So now, whenever someone first signs up, they go to verify_user_email_path. If they are logging in any other time, they go to the root_url.
Thanks, everyone!
Your OmniauthCallbacksController doesn't use the method after_sign_up_path_for so obviously you don't get the redirection you want.
Also, that class_eval thing is completely unnecessary. Here's how that controller should look:
class CustomDeviseControllers::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def all
omniauth = env["omniauth.auth"]
#user = User.from_omniauth(omniauth)
if #user.persisted?
sign_in #user
set_flash_message(:notice, :success, kind: omniauth.provider.capitalize) if is_navigational_format?
redirect_to verify_user_email_path
else
session["devise.#{omniauth.provider}_data"] = omniauth
redirect_to new_user_registration_url
end
end
alias_method :facebook, :all
alias_method :twitter, :all
end
Newbie here , i have omniauth-facebook setup in an application , every thing working fine , my only issue i want to redirect to another page after the authentication ,but i can't quite figure it out .
my first solution was to add a route to match the auth/facebook/callback to "sessions#new " it's not working . other thing i try is to add a redirect in the controller , not working also , what is the proper to redirect to a specific page ?
controller
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
# You need to implement the method below in your model (e.g. app/models/user.rb)
#user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)
if #user.persisted?
sign_in_and_redirect , :event => :authentication #this will throw if #user is not activated
set_flash_message(:notice, :success, :kind => "sign in successfuly") if is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
end
routes
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
thanks for any help .
When your get user by find_for_facebook_oauth method then you can login with that user and use redirect_to for your desired path. You can do something like:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
# You need to implement the method below in your model (e.g. app/models/user.rb)
#user = User.find_for_facebook_oauth(request.env["omniauth.auth"], current_user)
if #user.persisted?
sign_in(#user)
redirect_to desired_path, notice: 'Signed in successfully.'
set_flash_message(:notice, :success, :kind => "sign in successfuly") if is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
end