为什么validates_uniqueness_of在before_create之前运行?

时间:2013-02-11 21:27:32

标签: ruby-on-rails ruby-on-rails-3

在我的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对一个null的代码进行查询,看起来像是一个浪费的查询。

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

有什么想法吗?感谢

3 个答案:

答案 0 :(得分:2)

您可能希望使用before_validation :assign_code,这样代码在验证之前就会被设置。

答案 1 :(得分:1)

第一个查询来自验证回调(在设置代码之前)并检查没有其他Invite具有空code。第二个来自Invite.where(:code => code).exists?

回调的顺序显示为here。所以我认为您应该将assign_code称为before_validation回调,而不是before_create。然后,您可以自己跳过检查,code是唯一的。

答案 2 :(得分:0)

为我的RESTful API实现一个AccessToken类,我在validates_presence_of和before_creation回调订单中遇到了同样的问题。
如上所述,我使用了before_validation而不是_create,但它给了我一个新问题:我的方法在每次更新时被调用,更改我的令牌密钥,然后超过用户设备保存的数据。
通过检查是否是新记录解决了这个问题:
self.token = SecureRandom.hex if new_record?