I'm getting the following error when trying to sign in through google+ using the google_oauth2 gem.
undefined method `find_for_google_oauth2' for #<Class:0x007ff70a337148>
Here's the three files I've altered for sign up.
user.rb
def google_oauth2
user = User.from_omniauth(request.env["omniauth.auth"])
if user.persisted?
flash.notice = "Signed in Through Google!"
sign_in_and_redirect user
else
session["devise.user_attributes"] = user.attributes
flash.notice = "You are almost Done! Please provide a password to finish setting up your account"
redirect_to new_user_registration_url
end
end
omniauth_callbacks_controller.rb
def google_oauth2
# You need to implement the method below in your model (e.g. app/models/user.rb)
#user = User.find_for_google_oauth2(request.env["omniauth.auth"], current_user)
if #user.persisted?
flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Google"
sign_in_and_redirect #user, :event => :authentication
else
session["devise.google_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
and I've added config.omniauth :google_oauth2 in my devise.rb file.
routes.rb
devise_for :users, :controllers => { :registrations => "registrations", :sessions => "sessions", :omniauth_callbacks => "users/omniauth_callbacks" }
You are calling find_for_google_oauth2 from the omniauth_callbacks_controller, but you are using the wrong method name google_oauth2. You should replace google_oauth2 with find_for_google_oauth2.
And it seems like the code in user.rb is incorrect because it contains the controller code. Do you see it looks exactly the same like your controller code? :)
Correct code for user.rb
def self.find_for_google_oauth2(access_token, signed_in_resource=nil)
data = access_token.info
user = User.where(:email => data["email"]).first
# Uncomment the section below if you want users to be created if they don't exist
# unless user
# user = User.create(name: data["name"],
# email: data["email"],
# password: Devise.friendly_token[0,20]
# )
# end
user
end
Read more here: https://github.com/zquestz/omniauth-google-oauth2#devise
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?
# ....
Trying to implement Stripe Connect, and am getting the following error when I click the "connect to stripe" button.
The action 'passthru' could not be found for OmniauthCallbacksController
users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def stripe_connect
#user = current_user
if #user.update_attributes({
provider: request.env["omniauth.auth"].provider,
uid: request.env["omniauth.auth"].uid,
access_code: request.env["omniauth.auth"].credentials.token,
publishable_key: request.env["omniauth.auth"].info.stripe_publishable_key
})
# anything else you need to do in response..
sign_in_and_redirect #user, :event => :authentication
set_flash_message(:notice, :success, :kind => "Stripe") if is_navigational_format?
else
session["devise.stripe_connect_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
end
models/user.rb
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable, :omniauth_providers => [:stripe_connect]
routes.rb
devise_for :users, controllers: { registrations: 'users/registrations', :omniauth_callbacks => "users/omniauth_callbacks" }
gemfile.rb
gem 'omniauth-stripe-connect'
initializers/stripe.rb
Rails.configuration.stripe = {
:publishable_key => ENV['PUBLISHABLE_KEY'],
:secret_key => ENV['SECRET_KEY']
}
Stripe.api_key = Rails.configuration.stripe[:secret_key]
initializers/devise.rb
config.omniauth :stripe_connect,
ENV['STRIPE_CONNECT_CLIENT_ID'],
ENV['STRIPE_SECRET_KEY'],
:scope => 'read_write',
:stripe_landing => 'register'
button link:
<%= link_to image_tag('blue-on-light.png'), user_stripe_connect_omniauth_authorize_path(:stripe_connect) %>
As I understand it with my noob Ruby mind, I need to define 'passthru'? how do I define it though? when I enter:
def passthru
end
the link doesn't work / the page reloads itself. Haven't been able to find a solution on here. What am I missing?
EDIT:
Changed my connect to stripe link to:
<%= link_to image_tag('blue-on-light.png'), "/users/auth/stripe_connect" %>
The link takes me to the connect to stripe page, but when I click the "connect to stripe" button, the page cant be found, and doesn't load or redirect.
Can you try changing
# app/controllers/omniauth_callbacks_controller.rb
class OmniauthCallbacksController < ApplicationController
def stripe_connect
....
to
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def stripe_connect
#user = User.find_for_stripe_connect(request.env['omniauth.auth'], current_user)
set_notice_and_redirect
end
private
def set_notice_and_redirect
if #user.persisted?
flash[:notice] = 'Successfully signed in'
set_flash_message(:notice, :success, :kind => "Stripe") if is_navigational_format?
else
session["devise.stripe_connect_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
end
and in your user model
# Checks if user exists, otherwise create it
def self.find_for_stripe_connect(access_token, _ = nil)
data = access_token.info
user = User.where(email: data['email']).first_or_create(
email: data['email'],
password: Devise.friendly_token[0, 20],
provider: request.env["omniauth.auth"].provider,
uid: request.env["omniauth.auth"].uid,
access_code: request.env["omniauth.auth"].credentials.token,
publishable_key: request.env["omniauth.auth"].info.stripe_publishable_key
)
user
end
and also sing in path
<%= link_to image_tag('blue-on-light.png'), user_stripe_connect_omniauth_authorize %>
I think you don't need to define a passthru action. If you see the below two in the routes it can work. Authorize path is for redirecting user to stripe and callback is for redirecting user from stripe back to your site
$ rake routes
user_stripe_connect_omniauth_authorize /auth/stripe_connect(.:format) ....
user_stripe_connect_omniauth_callback /auth/stripe_connect/callback(.:format) ....
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
for some reason my Omniauth Facebook login is redirecting to /users/sign_up#= - but otherwise appears to be working. I have this in routes.rb:
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
I have this in application.html.erb:
<%= link_to "", user_omniauth_authorize_path(:facebook, :origin=>"root_url") %>
<%= link_to(image_tag("FB-Login.png"),
user_omniauth_authorize_path(:facebook), :origin=>"root_url", class:"mycss") %>
I have this in application_controller.rb:
def after_sign_in_path_for(resource_or_scope)
Rails.logger.level = 0
logger.debug "after_sign_in_path_for"
logger.debug "Session: #{#session.inspect}"
logger.debug "omniauth.origin: #{omniauth.origin}"
logger.debug "root_url: #{root_url}"
## if request.env['omniauth.origin']
## request.env['omniauth.origin']
request.env['omniauth.origin'] || root_url
end
Funny thing is the log statements are not showing in the heroku logs - looks like after_sign_in_path_for is not called ??
Any help appreciated,
Slavko
Maybe that user already exist?
Try to check user existence prior to persistence:
def facebook
#user = User.from_omniauth(request.env["omniauth.auth"])
if #user
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
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