2016-12-28 61 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) 

但最好你的情況下,這本來應該是一個驗證之前保存到驗證是否有形成無限循環的任何記錄。

相關問題