ArgumentError: Wrong number of arguments in Google oauth callback

ArgumentError: Wrong number of arguments in Google oauth callback

我按照 this tutorial 将用户身份验证添加到我的 rails 应用程序。本教程使用 devise 和 google_oauth2.

当用户尝试使用 Google 登录时,用户在回调后遇到 ArgumentError。

错误:

用户模型和回调控制器之间出现问题,但我的滑雪板有点过头了,无法理解可能导致问题的原因。

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

猜测 (!!) 你是 运行 最新版本的 ruby:3.0.0,发布于2020 年 12 月,在编写该教程之后。

ruby 版本 3 中有一个重大的突破性变化:Keyword and positional arguments are now separated

该错误非常微妙,但它的发生是因为您的代码正在执行此操作:

User.from_google(
  {
    uid: auth.uid,
    email: auth.info.email,
    full_name: auth.info.name,
    avatar_url: auth.info.image
  }
)

(即传递一个 Hash 给方法),而不是这个:

User.from_google(
  uid: auth.uid,
  email: auth.info.email,
  full_name: auth.info.name,
  avatar_url: auth.info.image
)

(即将 关键字参数 传递给方法。)

解决这个问题很简单:您可以使用“double-splat”运算符 (**) 将散列转换为关键字参数:

user = User.from_google(**from_google_params)

如果您在学习这样的教程时不习惯对代码进行此类更正,那么使用较旧的 ruby 版本(例如 2.7)应该也完全没问题。我上面显示的代码的“固定”版本将在所有 ruby 版本上正常工作。