0

我开始观看 Ryan Bates关于如何将 Omniauth 与设计一起使用的教程(rails-cast 235 已修订)。我遇到了 user.rb 文件的问题。他在教程中展示的内容

devise :omniauthable, # ...

def self.from_omniauth(auth)
  where(auth.slice(:provider, :uid)).first_or_create do |user|
    user.provider = auth.provider
    user.uid = auth.uid
    user.username = auth.info.nickname
  end
end

def self.new_with_session(params, session)
  if session["devise.user_attributes"]
    new(session["devise.user_attributes"], without_protection: true) do |user|
      user.attributes = params
      user.valid?
    end
  else
    super
  end
end

def password_required?
  super && provider.blank?
end

def update_with_password(params, *options)
  if encrypted_password.blank?
    update_attributes(params, *options)
  else
    super
  end
end

对我不起作用,它显示一个 ActiveModel::ForbiddenAttributesError 并where(auth.slice(:provider, :uid)).first_or_create do |user|突出显示这行代码。我认为他的版本不起作用,因为我使用的是 Rails 5。无论如何我已经尝试修改 user.rb 文件。使用以下代码。

 def self.from_omniauth(auth)
  where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
  	user.email = auth.info.email
    user.password = Devise.friendly_token[0,20]
    user.provider = auth.provider
    user.uid = auth.uid
    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],
          provider: data["provider"],
          uid: data["token"],
          token: data["credentials"]["token"],
          secret: data["credentials"]["secret"]
        )
      end
    end
  end

def password_required?
  super && provider.blank?
end

def update_with_password(params, *options)
  if encrypted_password.blank?
    update_attributes(params, *options)
  else
    super
  end
end
end

我能够让 twitter auth 页面显示加载大约一分钟,然后在不登录且不显示任何错误消息的情况下重定向回我的用户注册页面。顺便说一句,有人知道如何使用 devise 登录 facebook。

4

1 回答 1

0

问题与auth您传递给的属性有关self.from_omniauth(auth)。你应该在你的服务器日志上设置一个binding.pryputs auth,看看这个变量的样子..

可能当该self.from_amniauth(auth)方法运行时auth.slice()它以某种方式运行错误

此外,该first_or_create方法可能正在创建用户,您可能会丢失某些内容,从而触发错误。所以尝试在调试显示中使用user.errors.full_messages

听到的想法是该方法旨在找到User或创建它。它是从控制器动作中调用的Users::OmniauthCallbacksController#facebook

requestrequest表示这是从您的服务器传出到facebooktwitter..

Facebook 或 Twitter 将使用 回复此问题requestAJAX response其中将包含您验证用户所需的信息。

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.from_omniauth(request.env["omniauth.auth"])

    if @user.persisted?
      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?, you probably saved the env variable
    else
      session["devise.facebook_data"] = request.env["omniauth.auth"]
      redirect_to new_user_registration_url
    end
  end

  def failure
    redirect_to root_path
  end, you probably saved the env variable
end

然后使用以下方法,您将从您的数据库where(provider: auth.provider, uid: auth.uid).first_or_create中创建user或创建它。find问题是你可能写错了这个方法或者用错误的参数调用它,或者你没有设置apitwitter 来正确工作......

来自https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview

这个动作有几个方面值得描述:

OmniAuth 从 Facebook 检索到的所有信息都可以在 request.env["omniauth.auth"] 处以散列形式获得。检查 OmniAuth 文档和每个 omniauth-facebook gem 的 README 以了解正在返回哪些信息。

找到有效用户后,可以使用以下两种 Devise 方法之一登录:sign_in 或 sign_in_and_redirect。传递 :event => :authentication 是可选的。仅当您希望使用 Warden 回调时才应该这样做。

也可以使用 Devise 的默认消息之一设置 Flash 消息,但这取决于您。

如果用户没有被持久化,我们会将 OmniAuth 数据存储在会话中。请注意,我们使用“设计”存储此数据。作为关键命名空间。这很有用,因为 Devise 会删除所有以“设计”开头的数据。每当用户登录时从会话中提取,因此我们会自动清理会话。最后,我们将用户重定向回我们的注册表单。

定义好控制器后,我们需要在我们的模型中实现from_omniauth方法(例如app/models/user.rb):

def self.from_omniauth(auth)
  where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
    user.email = auth.info.email
    user.password = Devise.friendly_token[0,20]
    user.name = auth.info.name   # assuming the user model has a name
    user.image = auth.info.image # assuming the user model has an image
    # If you are using confirmable and the provider(s) you use validate emails, 
    # uncomment the line below to skip the confirmation emails.
    # user.skip_confirmation!
  end
end

此方法尝试通过 provider 和 uid 字段查找现有用户。如果未找到用户,则使用随机密码和一些额外信息创建一个新用户。请注意,first_or_create 方法在创建新用户时会自动设置提供者和 uid 字段。first_or_create!方法的操作类似,只是如果用户记录验证失败,它将引发异常。

于 2017-08-30T04:05:53.273 回答