Reputation: 451
I followed this tutorial to add user authentication to my rails app. The tutorial uses devise and google_oauth2.
When a user attempts to sign in with Google, the user encounters an ArgumentError after callback.
Error:
Something is broken between the user model and the callback controller, but I'm a bit too over my skis to understand what might be causing the problem.
user.rb
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
devise :omniauthable, omniauth_providers: [:google_oauth2]
def self.from_google(email:, full_name:, uid:, avatar_url:)
create_with(uid: uid, full_name: full_name, avatar_url: avatar_url).find_or_create_by!(email: email)
end
end
omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def google_oauth2
user = User.from_google(from_google_params)
if user.present?
sign_out_all_scopes
flash[:success] = t 'devise.omniauth_callbacks.success', kind: 'Google'
sign_in_and_redirect user, event: :authentication
else
flash[:alert] = t 'devise.omniauth_callbacks.failure', kind: 'Google', reason: "#{auth.info.email} is not authorized."
redirect_to new_user_session_path
end
end
protected
def after_omniauth_failure_path_for(_scope)
new_user_session_path
end
def after_sign_in_path_for(resource_or_scope)
stored_location_for(resource_or_scope) || root_path
end
private
def from_google_params
@from_google_params ||= {
uid: auth.uid,
email: auth.info.email,
full_name: auth.info.name,
avatar_url: auth.info.image
}
end
def auth
@auth ||= request.env['omniauth.auth']
end
end
Upvotes: 0
Views: 562
Reputation: 28285
I am guessing (!!) that you are running the latest version of ruby: 3.0.0
, which was released in December 2020, after that tutorial was written.
There is a major, breaking change in ruby version 3: Keyword and positional arguments are now separated.
The error is very subtle, but it's happening because your code is doing this:
User.from_google(
{
uid: auth.uid,
email: auth.info.email,
full_name: auth.info.name,
avatar_url: auth.info.image
}
)
(i.e. Passing a Hash
to the method), instead of this:
User.from_google(
uid: auth.uid,
email: auth.info.email,
full_name: auth.info.name,
avatar_url: auth.info.image
)
(i.e. Passing keyword arguments to the method.)
Fixing this problem is easy: You can use the "double-splat" operator (**
) to convert a hash into keyword arguments:
user = User.from_google(**from_google_params)
If you are not comfortable making such corrections to the code when following a tutorial like this, it should also be perfectly fine to use an older ruby version (e.g. 2.7
). The "fixed" version of the code I have shown above will work fine on all ruby versions.
Upvotes: 3