我是ruby on rails的新手,我正试图在Facebook上使用oauth,但我收到了这个错误:undefined method 'persisted?' for nil:NilClass
。当我尝试使用Facebook登录时会发生这种情况。有什么想法吗?
模特:
usuarios.rb
class Usuario < ActiveRecord::Base
# Include default devise modules. Others available are:
# :c onfirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
devise :omniauthable, omniauth_providers: [:facebook]
def self.find_or_create_by_omniauth(auth)
usuario = Usuario.where(provider: auth[:provider], uid: [:uid]).first
return usuario if usuario
usuario = Usuario.create[
nombre: auth[:nombre],
apellido: auth[:apellido],
username: auth[:username],
email: auth[:email],
uid: auth[:uid],
prvider: auth[:provider],
password: Devise.friendly_token[0,20]
]
end
end
控制器
omniauth_callback_controller.rb
class OmniauthCallbacksController < ApplicationController
def facebook
auth = request.env["omniauth.auth"]
data = {
nombre: auth.info.first_name,
apellido: auth.info.last_name,
username: auth.info.nickname,
email: auth.info.email,
provider: auth.provider,
uid: auth.uid
}
@usuario = Usuario.find_or_create_by_omniauth(data)
if @usuario.persisted?
sign_in_and_redirect @usuario, event: :authentication
else
session[:omniauth_errors] = @usuario.errors.full_messages.to_sentence unless @usuario.save
session[:omniauth_data] = data
redirect_to new_usuario_registration_url
end
end
def failure
redirect_to new_usuario_registration_url
end
end
非常感谢任何帮助。
答案 0 :(得分:1)
create[]
而不是create()
。 ARSubClass.create[foo: 1, bar: 2, baz: 3]
等于
ARSubClass.create[ {foo: 1, bar: 2, baz: 3} ]
ARSubClass.create
尝试创建ARSubClass
的实例,但它失败了,因为我猜测验证并返回非持久记录。
然后用一个参数[]
{foo: 1, bar: 2, baz: 3}
调用方法instance[{foo: 1, bar: 2, baz: 3}] => nil
。
create
这样的create(...)
。 更多&#34; RailsWay&#34;方法是使用find_or_create_by来实施find_or_create_by_omniauth
。
请注意,如果您将一个块传递给find_or_create_by
,则只会在create
情况下进行评估。
where(foo: 'baz', bar: 'mar').first
,使用find_by(foo: 'baz', bar: 'mar')
@usuario
设置为实例变量(带@
前缀),如果您不打算在某些视图中使用它。 usuario = ...
,其范围仅在当前方法中。答案 1 :(得分:0)
find_or_create_by_omniauth
方法在创建新的Usuario时返回nil
。 rails方法返回方法中的最后一个语句,当您创建记录时,它返回nil。您只需在方法的末尾添加usuario
,例如:
def self.find_or_create_by_omniauth(auth)
usuario = Usuario.where(provider: auth[:provider], uid: [:uid]).first
return usuario if usuario
usuario = Usuario.create[
nombre: auth[:nombre],
apellido: auth[:apellido],
username: auth[:username],
email: auth[:email],
uid: auth[:uid],
prvider: auth[:provider],
password: Devise.friendly_token[0,20]
]
usuario
end
答案 2 :(得分:0)
你获得nil的原因是你使用括号而不是parens。
# creates two things
Thing.create [{ name: foo }, { name: bar}]
# => nil
当您执行Usuario.create[nombre: auth[:nombre],...
实际传递数组时 - ActiveRecord将尝试创建多条记录并始终返回nil。
此外,您的代码充斥着拼写错误ActiveRecord actually provides a few methods to do this with a lot less fuss:
.first_or_create(attributes, &block) # when you don't want duplicates
.first_or_inialize(attributes, &block) # very useful for updates
您还应该注意,omniauth创建的request.env["omniauth.auth"]
哈希遵循Auth Hash Schema - 您没有使用正确的密钥,因此模型中的许多属性最终都将为nil。
所以让重构.find_or_create_by_omniauth
:
def self.find_or_create_by_omniauth(auth)
self.where(auth.slice(:uid, :provider))
# see the auth hash schema for available keys
.create_with(auth[:info].slice(:email))
.first_or_create do |user|
user.nombre = auth[:nombre] # will most likely be nil!
user.apellido = auth[:apellido] # will most likely be nil!
user.password = Devise.friendly_token[0,20]
end
end
Hash#slice
是一个很酷的ActiveSupport方法,它允许您复制哈希值,但只能使用所需的键 - 而无需手动复制它:
hash = { a: 1, b: 2, c: 3}
{ a: hash[:a], c: hash[:c] } # wow, much typing, such boring
hash.slice(:a,:c)
# => { a: 1, c: 3}