2010-07-09 9 views
5

Digamos que tengo un objeto FireNinja < Ninja en mi base de datos, almacenado usando herencia de tabla única. Más tarde, me doy cuenta de que realmente es un WaterNinja < Ninja. ¿Cuál es la forma más limpia de cambiarlo a la subclase diferente? Mejor aún, me gustaría crear un nuevo objeto WaterNinja y simplemente reemplazar el viejo FireNinja en el DB, preservando la ID.Cambiar una clase de un objeto en ActiveRecord

Editar que sabe cómo crear el nuevo objeto de mi WaterNinja existente FireNinja, y también sé que puedo borrar el viejo y guardar una nueva melodía. Lo que me gustaría hacer es mutar la clase del elemento existente. Ya sea que haga eso creando un nuevo objeto y haciendo algo de magia ActiveRecord para reemplazar la fila, o haciendo algún tipo de cosa loca con el objeto mismo, o incluso eliminándolo y reinsertándolo con la misma identificación, es parte de la pregunta.

Respuesta

2

que tiene que hacer dos cosas:

  • Crear WaterNinja < Ninja
  • En ninjas mesa de ejecutar algo así como UPDATE ninjas SET (type = 'WaterNinja') WHERE (type = 'FireNinja')

Eso es todo.

Para hacer la conversión en tiempo de ejecución esto lo hará, pero no lo recomiendo.

class Ninja 
    def become_another_ninja(new_ninja_type) 
    update_attribute(:type, new_ninja_type) 
    self.class.find(id) 
    end 
end 

@water_ninja = @fire_ninja.become_another_ninja('WaterNinja') 

El problema con esto es que @fire_ninja ahora habrá un objeto de usar y tirar.

+0

Parece que estás respondiendo, "¿cómo convierto todas las' FireNinjas' a 'WaterNinjas'?" La respuesta aún funciona aunque cambie la condición a 'ID = myid'. Sí, había pensado en eso.También tendría que sacar el objeto después de la actualización para hacer algunos ajustes de campo específicos de WaterNinja, pero está bien. Esperaba algo un poco más limpio, sin embargo. –

+0

Veo lo que quieres decir. No recomiendo hacer esto, pero esto hará el truco: 'ninja_id = @ ninja.id; @ ninja.update_attribute (: type, 'WaterNinja'); @ninja = WaterNinja.find (ninja_id) ' –

+0

Editado para mostrar el método que describí. –

-1

Deberá definir un método WaterNinja#to_fireninja. Ruby no tiene forma de cambiar la clase de un objeto mientras lo mantiene el mismo objeto.

class WaterNinja < Ninja 
    def to_fireninja 
    FireNinja.new :name => name 
    end 
end 
+0

Eso creará el nuevo objeto, pero cuando llamo guardar, creará una fila diferente en la base de datos. Quiero reemplazar mi instancia persistente de FireNinja con mi nuevo objeto WaterNinja. –

+0

@Isaac: No creo que sea posible, a menos que pueda eliminar el WaterNinja y forzar a ActiveRecord a guardar el nuevo FireNinja con el mismo ID. – Adrian

+0

una de las formas en que se podría responder la pregunta es si podría decirme cómo guardar el nuevo ninja con una identificación existente. Me encantaría eliminar y volver a insertar. –

0

Favorecer la composición por herencia: debe usar el patrón de estrategia para cambiar este tipo de comportamiento en el tiempo de ejecución.

http://en.wikipedia.org/wiki/Strategy_pattern

+0

No necesariamente. Google para "remplazar el tipo con polimorfismo" y "reemplazar el tipo con la estrategia" por los patrones de refactorización. El uso de la estrategia abarca algunos casos, pero en otros uno preferiría la herencia. Estos patrones también se describen bien en el libro Refactoring (http://www.amazon.com/Refactoring-Ruby-Jay-Fields/dp/0321603508). – samuil

+0

Tengo buenas razones para usar la herencia independientemente del problema que presento arriba. No estoy construyendo changetypeofninja.com. –

7

Usted puede hacer su acto FireNinja como WaterNinja haciendo

@ninja.becomes(WaterNinja) 

Si desea cambiar de forma permanente las clases, a continuación, sólo sobrescribir el atributo type.

@ninja.type = "WaterNinja" 
@ninja.save! 
+0

Esta es la respuesta correcta, la respuesta aceptada no es tan buena porque no usa "se convierte" – Rob

Cuestiones relacionadas