find_or_create_by与before_save回调

时间:2013-12-09 17:39:13

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

我有一个模型,它使用回调来规范化其中一个参数,该参数是模型唯一键的一部分。但是当使用MyModel.find_or_create_by()时,回调不会在'发现'阶段发挥作用,只会在'创建'阶段发挥作用,为时已晚。

这样做有一种优雅的模式吗?一个人为的例子:

class CreateMyModels < ActiveRecord::Migration
  def change
    create_table :my_models do |t|
      t.float :value
    end
    add_index :my_models, :value, :unique => true
  end
end

class MyModel < ActiveRecord::Base
  before_save :quantize_value
  private
    def quantize_value
      self.value = ((self.value || 0.0) * 256.0).round / 256.0
    end
end

让我们试一试:

>> a = MyModel.find_or_create_by(:value => 0.501)
=> #<MyModel id: 1, value: 0.5>

到目前为止,这么好。如果我们find_or_create_by的值接近但不等于现有记录,我们希望找到现有记录。但相反,我们得到:

>> b = MyModel.find_or_create_by(:value => 0.5001)
PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint ...

我想要的 - 概念上 - 是在运行查找之前让quantize_value方法运行

当然我已经编写了一个自定义构造函数,它在运行find之前应用了quantize_value方法。但是如果经验教会了我什么,那就是Rails的开发人员已经编写了我认为我需要编写的代码,而创建我自己的构造函数就会复制他们的工作! :)

1 个答案:

答案 0 :(得分:0)

IMO,我会将量化逻辑从模型中移出,保存回调并手动完成。您将更加了解实际值而不是设置值,然后查看模型修改它。

如果你真的想在模型中保留逻辑,你可以覆盖属性的setter方法,如下所示:

def value=(val)
  self[:value] = quantitize_value(val)
end