2011-04-17 15 views
-1

私はツリーとして機能するfolderというモデルを持っています。モデルの中には、ある場所から別の場所にフォルダをコピーするインスタンスメソッドのコピーがあります。フォルダをコピーするときには、そのサブフォルダもコピーする必要があります。私の再帰関数は終了しません。私は間違って何をしていますか?

これは私のコードです:私は、ルートフォルダにフォルダ1をコピーすると、それが正常に動作します

Root folder-+ 
      | 
     Folder 1-+ 
        | 
       Folder 2-+ 
         | 
         Folder 3 

class Folder < ActiveRecord::Base 
    acts_as_tree :order => 'name' 
    before_save :check_for_parent 

    def copy(target_folder) 
    new_folder = self.clone 
    new_folder.parent = target_folder 
    new_folder.save! 

    # Copy sub-folders recursively 
    self.children.each do |folder| 
     folder.copy(new_folder) unless folder == new_folder 
    end 
    end 

    def check_for_parent 
    raise 'Folders must have a parent.' if parent.nil? && name != 'Root folder' 
    end 
end 

は今、次のような状況を考慮してください。また、フォルダ1をフォルダ2にコピーすると機能しますが、フォルダ1をフォルダ3にコピーすると、無限の再帰で終了します。コードでは:

f1 = Folder.find_by_name('Folder 1') 
f3 = Folder.find_by_name('Folder 3') 
f1.copy(f3) # Never stops 

このコードは、につながる:

Root folder-+ 
      | 
     Folder 1-+ 
        | 
       Folder 2-+ 
         | 
         Folder 3-+ 
           | 
          Folder 1-+ 
            | 
            Folder 2-+ 
              | 
             Folder 3-+ 
                | 
               Folder 1-+ 
                 | 
                Folder 2-+ 
                   | 
                  Folder 3-+ 
                    | 
                    Folder 1-+ 
                      | 
                      Etc. 

私は些細な何かを見下ろすのですが、私はちょうどそれを把握することはできません。私は何を間違えているのですか?

答えて

0

最初にコピーしたフォルダを追跡しなければなりませんでした。以下のコードは動作します。もちろん、誰かが改善の余地がある場合は、教えてください。

def copy(target_folder, originally_copied_folder = nil) 
    new_folder = self.clone 
    new_folder.parent = target_folder 
    new_folder.save! 

    originally_copied_folder = new_folder if originally_copied_folder.nil? 

    # Copy sub-folders recursively 
    self.children.each do |folder| 
     folder.copy(new_folder, originally_copied_folder) unless folder == originally_copied_folder 
    end 
    end 
0

再帰(つまり、事前順序再帰)を実装するループの前に、現在のフォルダのコピーを実行してください。

+0

正確にはどういう意味ですか?私はすでにループの前に現在のフォルダのコピーをやっているようです。 (メソッドの最初の3行で)コードを表示できますか?ありがとうございました! – Mischa

+0

申し訳ありませんが、私は "後"を意味しました。 – Marcin

1

あなたの再帰を行う前に、それは最初のリーフノードに到達するように、あなたの方法の順序を変更してみてください:

def copy(target_folder) 
    new_folder = self.clone 

    # Copy sub-folders recursively 
    self.children.each do |folder| 
    folder.copy(new_folder) unless folder == new_folder 
    end 

    new_folder.parent = target_folder 
    new_folder.save! 
end 

あなたの問題はあなたがフォルダ3」の下で「フォルダ1」を親を変更することによって始めているということです'その後、再帰呼び出しが実行されます。 'Folder 3'に到達すると、今度は 'Folder 1'が子としてなり、サイクルが継続されます。

+0

ありがとうございます。はい、私はすでにそれを試みましたが、その場合、 'before_save'のためにエラーが発生します。おそらく私の質問では、それをもっと明確にしておくべきでしょう。 – Mischa