Rails-如何删除除一个条件外的所有记录

时间:2019-01-15 16:38:30

标签: ruby-on-rails ruby

假设我有一张这样的桌子

    id user_id  value
     1   1       A
     2   1        A
     3   1       A
     4   1       A
     5   1       A
     6   1       A
     7   2       B
     8   2       B
     9   3       C

如您所见,该表中有很多重复项。对于每个重复项,我希望能够删除其中一个重复项,以便仍然为每个重复项记录保留一条记录。例如,对于具有user_id = 1value = A的重复记录,我希望能够删除除其中之一以外的所有记录,以便我仍然剩下一个具有user_id = 1值的记录。和value = A

1 个答案:

答案 0 :(得分:0)

同意moveson的观点,最好的方法是在数据库中定义索引以强制执行不同的记录或允许您添加uniqueness validator to the model

另一种选择是拦截ActiveRecord创建方法调用以防止重复:

class Example < ApplicationRecord
  def self.create( attributes = nil, &block )
    attributes.each {|attr| self.create(attr, &block) } if attributes.is_a? Array
    return if find_by attributes
    super attributes, &block
  end
end

这里的基本思想是,如果您已经在数据库中看到具有相同属性值的记录,则中止...但是然后让ActiveRecord通过用super调用它来继续进行所有繁重的工作。

如果由于某种原因您无法对数据库进行控制以防止输入重复项,则可以尝试创建类方法以定期从系统中清除重复项的方法。

下面是一个方法示例,该方法将遍历整个记录集并使用哈希值来跟踪它是否曾经查看过这些值,如果是,则将其删除:

class Example < ApplicationRecord
  def self.dedup
    distinct = {}
    all.each do |row|
      if distinct[row.user_id] && distinct[row.user_id] == row.value
        row.delete
      else
        distinct[row.user_id] = row.value
      end
    end
  end
end

然后可以这样称呼它:Example.dedup每当您希望清除重复的记录时。

对于那些希望在家中跟随的人,您可以使用以下迁移:

rails g model example user_id:integer value:string

和种子文件:

examples = Example.create([
  {user_id: 1, value: 'A'},
  {user_id: 1, value: 'A'},
  {user_id: 1, value: 'A'},
  {user_id: 1, value: 'A'},
  {user_id: 1, value: 'A'},
  {user_id: 1, value: 'A'},
  {user_id: 1, value: 'A'},
  {user_id: 2, value: 'B'},
  {user_id: 2, value: 'B'},
  {user_id: 3, value: 'C'},
])