2016-12-28 14 views
0

私は、from_urlto_urlという列を持つリダイレクトと呼ばれるテーブルを持っています。Railsの異なる列に同じ値のレコードを見つける

ユーザーをあるURLから別のURLにリダイレクトするために使用されます。

だから、例えば私が持っているかもしれません。これらが生成されるように、ユーザーがページのURLを変更した場合

id: 1 
from_url: /about-us 
to_url: /about 

を私は無限ループを防ぐためにしたいしかし、同じリダイレクトが(他の方法アラウンド作成する必要がありますCMSでは元の値に戻すことができます)。

ですから、例えば:このシナリオでは

id: 1 
from_url: /about-us 
to_url: /about 

id: 2 
from_url: /about 
to_url: /about-us 

我々は変更をキャッチする新しいリダイレクトでそれを置き換えてきたし、元のリダイレクトが今あるように、私は、最初のレコードを削除したいと思います正しいURLを再度入力してください。私のモデルでは

が、私は方法はさておき、むしろ厄介なもののループをネストから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

次の実装ではネストループは使用しませんが、ネストされたDBクエリを使用して競合を検出します(バックグラウンドジョブなどでこれを行うことをお勧めします)。あなたは、内側が参加できる

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

は以下の通りあなたの条件に自身の表をリダイレクトします。これは、ペアの配列を返す必要があり

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') 

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 

ARELフォームには、次のようなものになるだろうidsの。それぞれからの最大のIDを収集し、それらの行

Redirect.delete((pairs.collect {|pair| pair.sort.last}).uniq) 

を削除しかし、理想的に、あなたのケースのために、これは無限ループを形成するすべてのレコードがあるかどうかを確認するために保存する前に検証されている必要があります。

関連する問題