rcrusoe
rcrusoe

Reputation: 451

ArgumentError: Wrong number of arguments in Google oauth callback

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:

enter image description here

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

Answers (1)

Tom Lord
Tom Lord

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

Related Questions