2016-12-28 59 views
0

我有一个称为重定向的表,它具有列from_urlto_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_urlto_url将匹配在两个重定向上,两者都将被删除。我怎样才能使它只是删除后者?我不想依赖任何last方法,因为这可能不能保证。

回答

1

以下实现不使用嵌套循环,但使用嵌套的数据库查询来找出冲突(我希望你在后台作业或其他方面做到这一点)。

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 
0

可以内部联接本身与你的条件重定向表如下:

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) 

但最好你的情况下,这本来应该是一个验证之前保存到验证是否有形成无限循环的任何记录。

相关问题