22

estoy actualmente la clonación de una asociación de un solo nivel de esta manera:ActiveRecord: ¿Cómo puedo clonar las asociaciones anidadas?

class Survey < ActiveRecord::Base 
    def duplicate 
    new_template = self.clone 
    new_template.questions << self.questions.collect { |question| question.clone } 
    new_template.save 
    end 
end 

Así que los clones del Survey luego clona el Questions asociado con esa encuesta. Multa. Eso funciona bastante bien.

Pero lo que estoy teniendo problemas es que cada pregunta has_manyAnswers. Entonces Survey has_many Questions which has_many Answers.

No sé cómo clonar las respuestas correctamente. He intentado esto:

def duplicate 
    new_template = self.clone 

    self.questions.each do |question| 
    new_question = question.clone 
    new_question.save 

    question.answers.each do |answer| 
     new_answer = answer.clone 
     new_answer.save 
     new_question.answers << answer 
    end 

    new_template.questions << question 
    end 

    new_template.save 
end 

pero eso algunas cosas raras con realidad la sustitución de las respuestas originales a continuación, crear otros nuevos, así que deja de Identificación correspondan correctamente.

Respuesta

45

Uso deep_clonable gem

new_survey = original_survey.clone :include => [:questions => :answers] 
+17

Dios mío. te quiero. – Shpigford

+2

el método de clonación ha cambiado a dup. ver [el readme del repositorio] (https://github.com/moiristo/deep_cloneable) –

+6

Y ahora cambia a: new_survey = original_survey.deep_clone: ​​include => [: questions =>: answers] – halbano

3

También le recomendamos el Amoeba gem de ActiveRecord 3.2.

En su caso, es probable que desee utilizar las opciones nullify, regex o prefix disponibles en la configuración DSL.

Soporta fácil y automática la duplicación recursiva de has_one, has_many y has_and_belongs_to_many asociaciones, preprocesamiento de campo y una DSL configuración altamente flexible y potente que se puede aplicar tanto al modelo y sobre la marcha.

asegúrese de revisar la Amoeba Documentation pero el uso es bastante fácil ...

simplemente

gem install amoeba 

o añadir

gem 'amoeba' 

a su Gemfile

continuación, agregue el bloque ameba a su modelo y ejecutar el método dup como de costumbre

class Post < ActiveRecord::Base 
    has_many :comments 
    has_and_belongs_to_many :tags 

    amoeba do 
    enable 
    end 
end 

class Comment < ActiveRecord::Base 
    belongs_to :post 
end 

class Tag < ActiveRecord::Base 
    has_and_belongs_to_many :posts 
end 

class PostsController < ActionController 
    def some_method 
    my_post = Post.find(params[:id]) 
    new_post = my_post.dup 
    new_post.save 
    end 
end 

También puede controlar qué campos se copian de muchas maneras, pero por ejemplo, si se quería evitar que los comentarios puedan ser duplicados, sino que quería mantener las mismas etiquetas, se podría hacer algo como esto:

class Post < ActiveRecord::Base 
    has_many :comments 
    has_and_belongs_to_many :tags 

    amoeba do 
    exclude_field :comments 
    end 
end 

También puede preprocesar los campos para ayudar a indicar la singularidad con prefijos y sufijos, así como expresiones regulares. Además, también hay numerosas opciones para que pueda escribir en el estilo más legible para su propósito:

class Post < ActiveRecord::Base 
    has_many :comments 
    has_and_belongs_to_many :tags 

    amoeba do 
    include_field :tags 
    prepend :title => "Copy of " 
    append :contents => " (copied version)" 
    regex :contents => {:replace => /dog/, :with => "cat"} 
    end 
end 

copia recursiva de las asociaciones es fácil, basta con activar la ameba en niños modelos, así

class Post < ActiveRecord::Base 
    has_many :comments 

    amoeba do 
    enable 
    end 
end 

class Comment < ActiveRecord::Base 
    belongs_to :post 
    has_many :ratings 

    amoeba do 
    enable 
    end 
end 

class Rating < ActiveRecord::Base 
    belongs_to :comment 
end 

La configuración DSL tiene aún más opciones, así que asegúrese de revisar la documentación.

¡Disfrútalo! :)

+1

De hecho, probé esta joya. Es muy prometedor, pero aún no está listo. Tuve dos problemas, los cuales publiqué en el proyecto github, pero al final me rendí y escribí mi función de copia de forma manual, usando dup. ¡Espero volver a intentarlo en unos meses y tener mejor suerte! – Rob

-1

Usted puede también alias el método dup carriles, de la siguiente manera:

class Survey 
    has_many :questions, :inverse_of=>:survey, :autosave=>true 
    alias orig_dup dup 
    def dup 
     copy=orig_dup 
     copy.questions=questions 
     copy 
    end 
end 

class Questions 
    belongs_to :survey, :inverse_of=>:questions 
    has_many :answers, :inverse_of=>:question, :autosave=>true 
    alias orig_dup dup 
    def dup 
     copy=orig_dup 
     copy.answers=answers 
     copy 
    end 
end 

class Answer 
    belongs_to :question 
end 

y entonces usted puede hacer esto

aaa = Survey.find(123).dup 
aaa.save 
0

¿No debería ser ..

new_question.answers << new_answer 
end 

new_template.questions << new_question 
Cuestiones relacionadas