在我的invite.rb模型中,我有以下内容:
class Invite < ActiveRecord::Base
before_create :assign_code
validates_uniqueness_of :code, :case_sensitive => false, :message => "This invite code is taken!"
protected
# Create a safe random token and ensuring it's uniqueness for the model
def assign_code
begin
code = SecureRandom.urlsafe_base64
end while Invite.where(:code => code).exists?
self.code = code
end
问题出现在日志中,我看到以下内容。为什么rails对一个空代码进行查询,看起来像是一个浪费的查询。
Invite Exists (0.5ms) SELECT 1 AS one FROM "invites" WHERE "invites"."code" IS NULL LIMIT 1
Invite Exists (0.3ms) SELECT 1 AS one FROM "invites" WHERE "invites"."code" = 'mTGCX0yCyTgplGfGQ5hGeA' LIMIT 1
有什么想法吗?感谢
您可能希望使用before_validation :assign_code
,这样代码在验证之前就会被设置好。
第一个查询来自验证回调(在设置代码之前),并检查其他Invite
是否没有空的code
。第二个来自Invite.where(:code => code).exists?
。
此处显示了回调的顺序。所以我认为您应该调用assign_code
作为before_validation
回调,而不是before_create
。然后,您可以跳过检查code
是否唯一。
为我的RESTful API实现一个AccessToken类,我在validates_presence_of和before_creation回调顺序方面遇到了同样的问题
如上所述,我使用了before_validation而不是_create,但这给我带来了一个新问题:每次更新时都会调用我的方法,更改我的令牌密钥,然后使用户设备保存的数据过期
通过检查它是否是新记录来解决此问题:self.token = SecureRandom.hex if new_record?