Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails Activerecord返回现有记录(如果在创建或保存模型时存在) 问题_Ruby On Rails_Activerecord_Ruby On Rails 4 - Fatal编程技术网

Ruby on rails Activerecord返回现有记录(如果在创建或保存模型时存在) 问题

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相关的记录。我遇到的问题是,我希望随时返回一

只要在模型本身中使用验证对模型调用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