Ruby on rails Activerecord返回现有记录(如果在创建或保存模型时存在) 问题
只要在模型本身中使用验证对模型调用save(!)或create(!)时,我希望返回现有记录(如果存在),而不使用从外部控制器或关联模型创建的first_或_。如果不存在记录,则应创建/保存新记录并返回 细节 我正在从事一个RubyonRails4项目,在这个项目中,我有一个存储Sha1散列的非常简单的模型。除了默认列之外,它还有一个名为“hexdigest”的单列,它是唯一的索引。Sha1与其他几个模型有很多关系,每个模型可能包含零个或多个与单个Sha相关的记录。我遇到的问题是,我希望随时返回一条现有记录(如果存在的话)。任何其他模型/控制器等都会调用Ruby on rails Activerecord返回现有记录(如果在创建或保存模型时存在) 问题,ruby-on-rails,activerecord,ruby-on-rails-4,Ruby On Rails,Activerecord,Ruby On Rails 4,只要在模型本身中使用验证对模型调用save(!)或create(!)时,我希望返回现有记录(如果存在),而不使用从外部控制器或关联模型创建的first_或_。如果不存在记录,则应创建/保存新记录并返回 细节 我正在从事一个RubyonRails4项目,在这个项目中,我有一个存储Sha1散列的非常简单的模型。除了默认列之外,它还有一个名为“hexdigest”的单列,它是唯一的索引。Sha1与其他几个模型有很多关系,每个模型可能包含零个或多个与单个Sha相关的记录。我遇到的问题是,我希望随时返回一
Sha1#save
或Sha1。create
等。我一直在尝试在模型本身中执行此操作,但尚未找到解决此问题的好方法
以下是模型的简单表示(实际模型的额外复杂性很小):
它的简单效果是确保新记录的关联Sha1在保存时解析为现有Sha1(如果存在)
但是,如果我尝试从其他地方(在测试、控制器或其他代码中)手动创建/保存Sha1,它将失败,因为第一个\u或\u创建没有直接在模型上解析:
Sha1.create(hexdigest: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33')
Sha1.create(hexdigest: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33') # results in a record not unique error
通过覆盖Sha1模型上的create,我成功地解决了create
上的问题:
def self.create(attributes, &block)
first || super
end
def self.create!(attributes, &block)
first || super
end
但是,当ActiveRecord在create
和save
上执行不同的路径时,保存时仍然会出现问题。因此,以下操作仍然失败,但有一个例外:
Sha1.new(hexdigest: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33').save
Sha1.new(hexdigest: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33').save # results in a record not unique error
它已经感觉像是一个黑客覆盖创建,但我还没有找到更好的方法来做到这一点。现在看来,我还需要覆盖save
和save代码>,但尚未成功完成此操作。最好使用回调,但回调只允许通过返回false或引发异常来转义create/save,这将导致在通过关联自动保存/创建Sha1时回滚整个事务
我对此做了几次尝试,BelongsToSha关注点是迄今为止最好的解决方案,但并非在上述所有情况下都有效。我不想引起错误或valid?#=>false
当试图保存或创建重复记录时;相反,我只想在所有情况下返回现有的。您想使用以下命令:find\u或\u create\u by
Sha1.find_or_create_by(hexdigest: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33')
它将根据hexidigest查找或创建Sha1记录并返回实例
首先,希望您的hexdigest列上有一个SQL约束。Ruby回调无法以原子方式验证唯一性。让我重复一遍。Ruby回调无法原子地验证唯一性
现在,对于您的问题,我要做的是,在您的sha1模型上创建一个新的保存方法
def save_unique!
while
self.hexdigest = Digest::MD5.hexdigest(rand(123123)) if self.hexdigest.nil?
self.save!
break
rescue ActiveRecord::RecordNotUnique
end
这递归地保证了唯一性不幸的是,上述两个答案实际上都没有解决我原来的问题。经过大量的尝试和错误,我发现在我的原始帖子中提到的ActiveSupport::Concern方法似乎是我能够实现的最接近/最好的解决方案
Sha1.find_or_create_by(hexdigest: '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33')
def save_unique!
while
self.hexdigest = Digest::MD5.hexdigest(rand(123123)) if self.hexdigest.nil?
self.save!
break
rescue ActiveRecord::RecordNotUnique
end