I'm getting this error:
The action 'github' could not be found for Users::OmniauthCallbacksController
I've looked everywhere and tried the other suggestions on other peoples posts.
This was the post on stack overflow but they had a typo and I didn't have that same error.
Devise OmniauthsController not being used
This recommendation said to check rake routes but my routes match what I'm pointing to.
https://github.com/plataformatec/devise/issues/1566
Most of the other links were all similar issues and I double checked the info with mine, changed stuff and still getting errors.
Info about my code.
gemfile:
gem 'omniauth-github'
config/routes.rb:
devise_for :users, :controllers => { :omniauth_callbacks => 'users/omniauth_callbacks' }
Users::OmniauthCallbacksController:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def github
#user = User.from_omniauth(request.env["omniauth.auth"])
if #user.persisted?
sign_in_and_redirect #user, event: :authentication
set_flash_message(:notice, :success, kind: "Github") if is_navigational_format?
else
redirect_to root_path
end
end
end
User Model:
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable, :omniauth_providers => [:github]
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.email = auth.info.email
user.uid = auth.uid
user.provider = auth.provider
user.password = Devise.friendly_token[0, 20]
user.name = auth.info.name #assuming the user model has a name
user.oauth_token = auth.credentials.token
user.image = auth.info.image #assuming the user model has an image
user.save!
end
end
Devise initializer:
config.omniauth :github, Rails.application.secrets.github_client_id, Rails.application.secrets.github_client_secret, scope: 'user:email'
Not sure what to do since I have the method in the Users::OmniauthCallBacks controller? Am I missing something? I've been combing through for an entire day.
Update: somehow I had 2 users folders in the controller but one was hidden? It must have gotten messed up when I reverted to a previous repo last night. Once I removed the folder all was good!
Related
I know this has been asked many times, but the answers are never fully acceptable to me.
So I am following Ryan Bates' Railscast about this topic, and mixing that with the official Devise Omniauth guide (that is based on FB), but I am just not getting it to work like I expect, so I would love some help.
I have a Users::OmniauthCallbacksController that looks like this:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def all
#user = User.from_omniauth(request.env["omniauth.auth"])
if #user.persisted?
sign_in_and_redirect root_path, :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")
flash[:notice] = flash[:notice].to_a.concat resource.errors.full_messages
redirect_to new_user_registration_url
end
end
alias_method :twitter, :all
def failure
redirect_to root_path
end
end
Then I also have two methods on my User.rb
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.update(
email: auth.info.email,
password: Devise.friendly_token[0,20],
username: auth.info.nickname,
remote_avatar_url: auth.info.image,
token: auth.credentials.token,
secret: auth.credentials.secret
)
end
end
def self.new_with_session(params, session)
super.tap do |user|
if data = session["devise.twitter_data"]
# user.attributes = params
user.update(
email: params[:email],
password: Devise.friendly_token[0,20],
username: data["info"]["nickname"],
remote_avatar_url: data["info"]["image"],
token: data["credentials"]["token"],
secret: data["credentials"]["secret"]
)
end
end
end
I run into a variety of problems. The most immediate is because I am setting the password, the user doesn't know the password when they try to login (and I don't auto sign them in upon confirmation).
But if I don't set the password, it doesn't ask them to set the password...so that's kinda weird too.
These are my devise settings on my User model:
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable, :omniauthable, :omniauth_providers => [:twitter]
validates :username,
presence: true,
uniqueness: {
case_sensitive: false
}
validate :validate_username
def validate_username
if User.where(email: username).exists?
errors.add(:username, :invalid)
end
end
So my question is this, when someone signs up via Twitter, do they need to enter a password? I automatically send them to the registration/new.html.erb anyway because Twitter doesn't return an email value. But I am trying to just get the process working first, before optimizing it.
How do I deal with the password issue?
Edit 1
For more clarity, I will have to deal with this password_required issue regardless of the OAuth provider.
So how do I override that requirement for all OAuth providers?
You should add the following method to the User class:
def password_required?
(provider.blank? || uid.blank?) && super
end
Since Twitter doesn't return the user's email, you may also want to tweak that email validation, but redirecting the user to registration/new.html.erb like you are already doing seems like the correct approach to me.
I'm playing around with the omniauth-facebook gem to log into a devise session through a facebook account. When I click the "Sign in with facebook" link, everything goes well: a new account is created, I'm signed in and bounce back to the homepage with a message confirming my new session (very good!).
Problem: However when an account already exists, upon clicking the link I am redirected to the user/sign_up page. I've been following this documentation from the Devise wiki. There is a good deal of documentation on similar errors here, here, here and here. Each of the solutions, however, are already implemented in my app (as far as I can tell) OR (in the case of the last link) seem to be based on an older configuration model that seems sufficiently different from the wiki that I'm not sure it's applicable.
My best guess is that it has something to do with the callbacks controller, as #user.persisted? seems to be coming up false.This leads me to believe that my definition of #user is not correct. See below:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
logger.debug "Inside facebook"
# You need to implement the method below in your model (e.g. app/models/user.rb)
#user = User.from_omniauth(request.env["omniauth.auth"])
logger.debug "User is #{#user}"
if #user.persisted?
logger.debug "#user.persisted?"
debugger
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?
logger.debug "user exists"
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
def failure
redirect_to root_path, alert: "Login failed"
end
end
Additionally, my user model is as follows:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable, :omniauth_providers => [:facebook]
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.provider = Devise.friendly_token[0,20]
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
user.fname = auth.info.first_name
user.lname = auth.info.last_name
end
end
end
Any suggestions would be certainly welcome! Thanks in advance.
Try Something Like This
class Authentication < ActiveRecord::Base
belongs_to :user
# validates :provider, :uid, :presence => true
def self.from_omniauth(auth)
authenticate = where(provider: auth[:provider], :uid=>auth[:uid]).first_or_initialize
if authenticate.user
authenticate.provider = auth[:provider]
authenticate.uid =auth[:uid]
else
user = User.find_or_initialize_by(:email => email)
authenticate.provider = auth[:provider]
user.email = email
user.first_name = first_name
user.last_name = last_name
user.social_image = image
user.password = Devise.friendly_token.first(8)
user.save(validate: false)
if user.errors.any?
return user
else
authenticate.user_id = user.id
end
end
authenticate.save
authenticate.user
end
end
Try this
def after_sign_in_path_for(resource)
super resource
end
From what i perceived that you are not going to your landing page
from_omniauth never finds an existing facebook user because you are overwriting the provider attribute:
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
searches for a user with provider 'facebook' in this case, but none can be found:
user.provider = Devise.friendly_token[0,20]
changes the provider to some random token
just remove that line and it should work properly
I don't know where comes from this following error message from Devise + omniauth Google:
"Could not authenticate you from GoogleOauth2 because "Invalid credentials".
Is it came from a occurred manipulation with Google API? Or came from a mistake with my code?
Is there a right convention to call API ID and SECRET KEYS in application.yml
I checked numerous tutorials but no answers...
Please could you guide me. Thank you for your clear explanation.
Here is my controller code
def google_oauth2
user = User.find_for_google_oauth2(request.env['omniauth.auth'])
if user.persisted?
sign_in_and_redirect user, event: :authentication
set_flash_message(:notice, :success, kind: 'GoogleOauth2') if is_navigational_format?
else
session['devise.google_oauth2_data'] = request.env['omniauth.auth']
redirect_to new_user_registration_url
end
end
Here is the Model :
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable, omniauth_providers: [:facebook, :google_oauth2]
has_and_belongs_to_many :oauth_credentials
def self.find_for_google_oauth2(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.email = auth.info.email
user.password = Devise.friendly_token[0,20] # Fake password for validation
user.first_name = auth.info.name
user.last_name = auth.info.nickname
user.picture = auth.info.image
user.token = auth.credentials.token
end
end
Thank you for your help.
I'm trying to do OmniAuth in rails 4 for spotify. I almost have it but for some reason, the redirect URI isn't working. I am using Devise with omniauth These are my files:
User.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable, :omniauth_providers => [:spotify]
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.email = auth.info.email
user.password = Devise.friendly_token[0,20]
end
end
end
My Callbacks controller to handle callbacks
class CallbacksController < Devise::OmniauthCallbacksController
def spotify
#user = User.from_omniauth(request.env["omniauth.auth"])
sign_in_and_redirect #user
end
end
My Devise.rb snippet:
config.omniauth :spotify, client_id, client_secret,scope: 'playlist-read-private user-read-private user-read-email'
My Routes.rb
Rails.application.routes.draw do
devise_for :users, :controllers => { :omniauth_callbacks => 'callbacks' }
get '/users/auth/callback', to: 'callbacks#spotify'
end
And lastly, the link leading up to the login:
<%= link_to 'Sign in with Spotify', user_omniauth_authorize_path(:spotify) %>
But for some reason, whenever I try to log into spotify, it says invalid redirect URI
OK, I figured out a solution to my particular problem:
When it was giving me the error of "invalid redirect URI", I looked at the URI it was trying to go to and I simply used that.
Then I got a second error which gave me a SSL Cert error so I used "gem certified" to fix that. THEN, it gave me a third problem of unauthorized access (the callback returned a failed request). What was happening was that I was trying to use OmniAuth twice. I had two files:
A) OmniAuth.rb
and B) Devise.rb
Both of these files were making API calls and it was messing it up. So to anyone having this problem- don't use both omniauth and devise. Honestly, after the first initial hiccup, I found devise to be way more useful than making your own User model and applying omniauth to that. Devise is more comprehensive!
I am setting up devise with omniauth facebook gem to build a signup system. Users can either register with email or connect with their facebook account.
If an email registered user signs in with the facebook account, I check if the email address is already registered and connect these two accounts, and then log the user in.
This whole scenario works already. The user entry is updated with the new omniauth data of facebook. I get this error, when facebooks sends the callback (data from facebook is saved to db successfully):
RuntimeError in CallbacksController#facebook
Could not find a valid mapping for true
Extracted source (around line #5):
class CallbacksController < Devise::OmniauthCallbacksController
# Define each provider for omniauth here (def twitter...)
def facebook
#user = User.from_omniauth(request.env["omniauth.auth"])
sign_in_and_redirect #user
end
end
user.rb modell looks like this:
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:omniauthable, :omniauth_providers => [:facebook]
def self.from_omniauth(auth)
user = where(provider: auth.provider, uid: auth.uid).first
unless user
user = where(email: auth.info.email).first_or_initialize
user.provider = auth.provider
user.uid = auth.uid
user.email = auth.info.email
user.name = auth.info.name
user.nickname = auth.info.nickname
user.first_name = auth.info.first_name
user.last_name = auth.info.last_name
user.location = auth.info.location
user.description = auth.info.description
user.image = auth.info.image
user.phone = auth.info.phone
user.urls = auth.info.urls
user.password = Devise.friendly_token[0,20]
user.save!
end
end
end
routes.rb
Rails.application.routes.draw do
devise_for :users, :controllers => { :omniauth_callbacks => "callbacks" }
resources :auctions do
resources :comments
end
root 'welcome#index'
get '/', :to => 'welcome#index'
end
Your self.from_omniauth method in your User class is returning true, instead of a User model. It's because the return value of a method in Ruby is the result of the last line evaluated, and in this case user.save! is the last line that runs. The "Could not find a valid mapping for true" error is a result of passing true into sign_in_and_redirect; you can see in the Devise source that the first argument is passed into Devise::Mapping.find_scope!.
The solution's simple - make sure that you're returning your user model in from_omniauth:
def self.from_omniauth(auth)
user = where(provider: auth.provider, uid: auth.uid).first
unless user
user = where(email: auth.info.email).first_or_initialize
user.provider = auth.provider
user.uid = auth.uid
user.email = auth.info.email
user.name = auth.info.name
user.nickname = auth.info.nickname
user.first_name = auth.info.first_name
user.last_name = auth.info.last_name
user.location = auth.info.location
user.description = auth.info.description
user.image = auth.info.image
user.phone = auth.info.phone
user.urls = auth.info.urls
user.password = Devise.friendly_token[0,20]
user.save!
end
user # Make sure we return the user we constructed.
end