ActiveRecord 验证传递 Null 而不是参数
ActiveRecord Validation Passing Null instead of Parameter
我正在尝试将 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
所有这些参数都存在,但是当它在创建过程中进行验证时,它会为电子邮件传递 NULL 和 fb_id。
从 Rails 输出:
FBUser Exists (0.4ms) SELECT 1 AS one FROM "fb_users" WHERE "fb_users"."fb_id" IS NULL LIMIT 1
FBUser Exists (0.2ms) SELECT 1 AS one FROM "fb_users" WHERE "fb_users"."email" IS NULL LIMIT 1
FBUser Exists (0.4ms) SELECT 1 AS one FROM "fb_users" WHERE "fb_users"."access_token" = 'EAAEDVcUvjT4BACT8es...
SQL (0.2ms) INSERT INTO "fb_users" ("fb_id", "email", "created_at", "updated_at") VALUES (, , , ) RETURNING "id" [["fb_id", "101564XXXXXXX688"], ["email", "XXXX68@facebook.com"], ["created_at", "2018-08-17 02:42:20.440539"], ["updated_at", "2018-08-17 02:42:20.440539"]]
我知道这是唯一性验证,因为如果我删除它,那些查询就会消失。实际上,唯一性验证没有做任何事情。我不知道为什么访问令牌根本没有传递给 INSERT 语句,但这是次要问题。
我已将“param[]”参数传递给一个变量,但没有执行任何操作。我很困惑为什么它为唯一性检查传递 NULL 而不是电子邮件和 fb_id 的值,而不是访问令牌。它传递 INSERT 中的值,此后立即从同一创建方法调用!
我用相同的 fb_id 和电子邮件创建了多个 FBUser,但 table 被创建为:
create_table :fb_users do |t|
t.string :fb_id, null: false, unique: true
t.string :email, unique: true
t.string :access_token ...
更多的陌生感...
ActiveRecord 属性(即存储在数据库中的列)与实例变量不同。你有这个:
attr_reader :email, :fb_id
在你的模型中。这只是 shorthand 用于:
def email
@email
end
def fb_id
@fb_id
end
所以无论何时有人说 fbuser.email
或 fbuser.fb_id
,您都会查看实例变量。但是,当你说:
FBUser.create({
fb_id: params[:userID],
email: params[:email],
...
})
ActiveRecord 将调用 fb_id=
和 email=
方法将这两个值存储在模型实例中。 ActiveRecord 为您创建了这些修改器方法,它们将更新 属性 ,而不是 实例变量 。通常 AR 还会创建 fb_id
和 email
方法来读取这些属性,但您已经使用 attr_reader
调用创建了这些方法。
结果是 fbuser.email
将从 @email
读取,但 fbuser.email = something
将写入其他内容,因此 fbuser.email
将始终为您提供 nil
。 fbuser.fb_id
.
同样
您可能想要完全摆脱 attr_reader
和 attr_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
我正在尝试将 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
所有这些参数都存在,但是当它在创建过程中进行验证时,它会为电子邮件传递 NULL 和 fb_id。 从 Rails 输出:
FBUser Exists (0.4ms) SELECT 1 AS one FROM "fb_users" WHERE "fb_users"."fb_id" IS NULL LIMIT 1
FBUser Exists (0.2ms) SELECT 1 AS one FROM "fb_users" WHERE "fb_users"."email" IS NULL LIMIT 1
FBUser Exists (0.4ms) SELECT 1 AS one FROM "fb_users" WHERE "fb_users"."access_token" = 'EAAEDVcUvjT4BACT8es...
SQL (0.2ms) INSERT INTO "fb_users" ("fb_id", "email", "created_at", "updated_at") VALUES (, , , ) RETURNING "id" [["fb_id", "101564XXXXXXX688"], ["email", "XXXX68@facebook.com"], ["created_at", "2018-08-17 02:42:20.440539"], ["updated_at", "2018-08-17 02:42:20.440539"]]
我知道这是唯一性验证,因为如果我删除它,那些查询就会消失。实际上,唯一性验证没有做任何事情。我不知道为什么访问令牌根本没有传递给 INSERT 语句,但这是次要问题。
我已将“param[]”参数传递给一个变量,但没有执行任何操作。我很困惑为什么它为唯一性检查传递 NULL 而不是电子邮件和 fb_id 的值,而不是访问令牌。它传递 INSERT 中的值,此后立即从同一创建方法调用!
我用相同的 fb_id 和电子邮件创建了多个 FBUser,但 table 被创建为:
create_table :fb_users do |t|
t.string :fb_id, null: false, unique: true
t.string :email, unique: true
t.string :access_token ...
更多的陌生感...
ActiveRecord 属性(即存储在数据库中的列)与实例变量不同。你有这个:
attr_reader :email, :fb_id
在你的模型中。这只是 shorthand 用于:
def email
@email
end
def fb_id
@fb_id
end
所以无论何时有人说 fbuser.email
或 fbuser.fb_id
,您都会查看实例变量。但是,当你说:
FBUser.create({
fb_id: params[:userID],
email: params[:email],
...
})
ActiveRecord 将调用 fb_id=
和 email=
方法将这两个值存储在模型实例中。 ActiveRecord 为您创建了这些修改器方法,它们将更新 属性 ,而不是 实例变量 。通常 AR 还会创建 fb_id
和 email
方法来读取这些属性,但您已经使用 attr_reader
调用创建了这些方法。
结果是 fbuser.email
将从 @email
读取,但 fbuser.email = something
将写入其他内容,因此 fbuser.email
将始终为您提供 nil
。 fbuser.fb_id
.
您可能想要完全摆脱 attr_reader
和 attr_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