ActiveRecord验证传递空值而不是参数

时间:2018-08-17 02:49:31

标签: ruby-on-rails ruby-on-rails-4 activerecord

我正在尝试将Facebook登录信息集成到我的网站中。

到目前为止,我已经建立了这样的模型(我可以添加一个更好的电子邮件验证器):

class FBUser < ActiveRecord::Base

    attr_accessor :access_token, :expires_in, :reauthorize_in
    attr_reader :email, :fb_id

    validates :fb_id, :email, :access_token, allow_blank: false, uniqueness: true
    validates :access_token, :expires_in, :reauthorize_in, presence: true

end

当用户使用Facebook登录时,它将返回的参数传递给此开发中的控制器功能:

def fb_login
   params[:email] ||= params[:userID][-7...-1] + "@facebook.com"
   fb_user = FBUser.create({
   fb_id: params[:userID],
   email: params[:email],
   access_token: params[:accessToken],
   expires_in: params[:expiresIn],
   reauthorize_in: params[:reauthorize_required_in]
  })
  sign_in!(fb_user)
  render json: fb_user
end

所有这些参数都存在,但是在创建过程中进行验证时,它将为电子邮件和fb_id传递NULL。 从Rails输出:

  

FBUser存在(0.4ms)从“ fb_users”到“ fb_users”的“ SELECT 1”为1。“ fb_id”为NULL LIMIT 1

     

FBUser存在(0.2ms)从“ fb_users”到“ fb_users”的“ SELECT 1”为1。“ email”为NULL LIMIT 1

     

FBUser存在(0.4毫秒)从“ fb_users”中的“ fb_users”中选择1作为一个。“ access_token” ='EAAEDVcUvjT4BACT8es ...

     

SQL(0.2ms)插入“ fb_users”(“ fb_id”,“电子邮件”,“ created_at”,“ updated_at”)值($ 1,$ 2,$ 3,$ 4)返回“ id” [[[“ fb_id”, “ 101564XXXXXXX688”],[“电子邮件”,“ XXXX68@facebook.com”],[“ created_at”,“ 2018-08-17 02:42:20.440539”],[“ updated_at”,“ 2018-08-17 02 :42:20.440539“]]

我知道这是唯一性验证,因为如果删除它,那些查询就会消失。实际上,唯一性验证没有做任何事情。我不知道为什么访问令牌根本没有传递给INSERT语句,但这是次要问题。

我已经将“ param []”参数传递给了一个变量,但没有执行任何操作。我很困惑为什么它为唯一性检查而不是email和fb_id的值而不是访问令牌的值传递NULL。此后,它将传递从同一create方法调用的INSERT中的值!

我正在使用相同的fb_id和电子邮件创建多个FBUser,但是该表的创建方式为:

create_table :fb_users do |t|
      t.string :fb_id, null: false, unique: true
      t.string :email, unique: true
      t.string :access_token ...

更多陌生人...

1 个答案:

答案 0 :(得分:1)

ActiveRecord属性(即存储在数据库中的列)与实例变量不同。你有这个:

attr_reader :email, :fb_id

在您的模型中。这只是简写:

def email
  @email
end

def fb_id
  @fb_id
end

因此,每当有人说fbuser.emailfbuser.fb_id时,您都会在查看实例变量。但是,当您说:

FBUser.create({
  fb_id: params[:userID],
  email: params[:email],
  ...
})

ActiveRecord将调用fb_id=email=方法,将这两个值存储在模型实例中。 ActiveRecord为您创建了这些mutator方法,它们将更新属性,而不是实例变量。通常,AR还会创建fb_idemail方法来读取这些属性,但是您已经通过attr_reader调用创建了这些方法。

结果是fbuser.email将从@email读取,但是fbuser.email = something会写入其他内容,因此fbuser.email总是会给您nil。对于fbuser.fb_id同样。

您可能希望完全摆脱attr_readerattr_accessor的调用,并使模型看起来像这样:

class FBUser < ActiveRecord::Base
  validates :fb_id, :email, :access_token, allow_blank: false, uniqueness: true
  validates :access_token, :expires_in, :reauthorize_in, presence: true
end