2011-05-12 13 views

Respuesta

24

Usted puede obtener un buen uso de la Amoeba gem de ActiveRecord 3.2.

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 

Su nuevo puesto debe tener todas las etiquetas que se asociaron originalmente con él, y todos los comentarios debe ser duplicada también. Puede desactivar la duplicación de varios registros a través de la DSL, que se puede leer en la documentación, pero por ejemplo, si desea mantener las etiquetas, pero no los comentarios que usted podría hacer algo como esto:

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

    amoeba do 
    include_field :comments 
    end 
end 

o el uso de la sintaxis exclusiva

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

    amoeba do 
    exclude_field :comments 
    end 
end 

o especificando cuáles son los tipos de campo para reconocer (y de ahí la copia)

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

    amoeba do 
    recognize :has_and_belongs_to_many 
    end 
end 

cada una de estas diferentes opciones debe volver sult en volver a asociar la nueva publicación con las mismas etiquetas que la publicación anterior, pero sin duplicar los comentarios.

Amoeba también recursivo automáticamente en los registros secundarios si se habilita

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 

Puede también campos de prefijo con algunos datos adicionales para indicar singularidad

class Post < ActiveRecord::Base 
    has_many :comments 

    amoeba do 
    enable 
    prepend :title => "Copy of " 
    end 
end 

y además de anteponer puedas también se agrega o ejecuta una expresión regular en un campo determinado

¡Disfrútalo! :)

+1

Guau esta joya es realmente increíble. Tuve que rodar mi propio sistema de duplicación y no funcionaba, pero tu gema funcionó muy bien. – Amala

+3

¿Debería el .dup en el ejemplo ser "new_post = my_post.amoeba_dup", como se define en los documentos? – kibaekr

+5

@kibaekr de la historia de README que encontré "A partir del 11 de diciembre de 2012 Amoeba ya no anula el método' ActiveRecord :: Base # dup' incorporado y en su lugar implementa su propio método llamado 'amoeba_dup' ..." – Sam

18

Tendrá que escribir su propio método clone_with_associations que pase por un conjunto específico de asociaciones enumeradas. Teóricamente, podría escribir algo genérico que utiliza reflect_on_all_associations, pero tendría que hacer lo mismo en los objetos asociados, y esto terminaría creando un bucle que genera una cantidad infinita de registros.

Así que solo escriba el suyo. Algo así como

#in Blerg 
    has_many :foos 
    has_many :bars #bars also have many chickens which we want to copy over as well 
    def clone_with_associations 
    new_blerg = self.dup 
    new_blerg.save 
    #simple association 
    new_blerg.foos = self.foos 
    #two-level association 
    self.bars.each do |bar| 
     new_bar = bar.clone 
     new_bar.save 
     new_bar.chickens = bar.chickens 
     new_blerg.bars << bar 
    end 
    new_blerg 
    end 

ahora que se puede hacer

@new_blerg = Blerg.find(1).clone_with_associations 
+20

Usted obtendrá un objeto original roto, ya que 'new_blerg.foos = self.foos' roba sus asociaciones. También necesitarías clonarlos. – RocketR

+1

Esta es la mejor respuesta. En mi humilde opinión, la propia en este caso, es mucho más limpia, más fácil, menos mágica que usar una gema. – hellion

+0

RocketR - buen punto. Creo que estaba asumiendo que la relación .foos era un "tiene y pertenece a muchos", en cuyo caso estaría bien, pero si foo pertenece_a blerg entonces sí, alteraría los foos asociados. –

15

Igualmente, esta gema parece funcionar bien: https://github.com/moiristo/deep_cloneable, y es bastante fácil de usar.

Sólo

gem ‘deep_cloneable’, ‘~> 1.4.0’

y luego:

pirate.deep_clone :include => :mateys

+3

Encontré esto más fácil de implementar que 'ameba '- no se requieren declaraciones en los modelos. – benjineer

+1

Sí, esto es mucho menos sobrecarga que ameoba, sin declaraciones ni DSL para aprender. Creo que es más "railsy" también. La flexibilidad también es sólida. Rails debería agregar esto como métodos AR. – bwest87

+1

Nueva joya favorita. –

Cuestiones relacionadas