在Rails的不同列中查找具有相同值的记录
问题描述:
我有一个称为重定向的表,它具有列from_url
和to_url
。在Rails的不同列中查找具有相同值的记录
它们用于将用户从一个网址重定向到另一个网址。
因此,例如,我可能有:
id: 1
from_url: /about-us
to_url: /about
不过,我想,以防止无限循环应该在同一重定向创建全能的方式等(因为这些是产生当用户更改URL的网页在CMS中,可以将其更改回原始值)。
因此,例如:
id: 1
from_url: /about-us
to_url: /about
id: 2
from_url: /about
to_url: /about-us
在这种情况下,我想删除第一条记录,因为我们已经有一个新的重定向取代它赶上变化,原来的重定向是现在再次修正网址。
在我的模型我有方法从嵌套循环是相当恶劣的所谓test_and_clean
def self.test_and_clean
redirects = Redirect.all
conflicts = []
redirects.each do |redirect|
redirects.each do |redirect2|
# if from_url has a matching to_url (causing a loop)
if redirect.from_url == redirect2.to_url
conflicts.push(redirect2)
end
end
end
# destroy all the conflicts
conflicts.each do |conflict|
conflict.destroy
end
end
除此之外,他们是这种方法的问题,最初的循环将找到重定向因为from_url
和to_url
将匹配在两个重定向上,两者都将被删除。我怎样才能使它只是删除后者?我不想依赖任何last
方法,因为这可能不能保证。
答
以下实现不使用嵌套循环,但使用嵌套的数据库查询来找出冲突(我希望你在后台作业或其他方面做到这一点)。
def self.test_and_clean
conflicts = []
# Find all the conflicts
Redirect.find_each do |redirect|
# Check if the current redirect was already detected as conflict
unless conflicts.include?(redirect)
conflict = Redirect.find_by(from_url: redirect.to_url, to_url: redirect.from_url)
conflicts.push(conflict) unless conflict.nil?
end
end
# destroy all the conflicts
conflicts.each do |conflict|
conflict.destroy
end
end
答
可以内部联接本身与你的条件重定向表如下:
SELECT r1.id, r2.id FROM redirects r1
INNER JOIN redirects r2 ON r1.from_url = r2.to_url
AND r1.to_url = r2.from_url
AND r1.id != r2.id
阿雷尔形式是什么如下:
Redirects.joins("inner join #{Redirect.table_name} as r2 ON
#{Redirect.table_name}.from_url = r2.to_url
AND #{Redirect.table_name}.to_url = r2.from_url
AND #{Redirect.table_name}.id != r2.id").pluck('redirects.id', 'r2.id')
这应返回对数组的ids。从每个收集的最大的ID,并删除这些行
Redirect.delete((pairs.collect {|pair| pair.sort.last}).uniq)
但最好你的情况下,这本来应该是一个验证之前保存到验证是否有形成无限循环的任何记录。