2010-07-09 12 views
5

Załóżmy, że mam obiekt FireNinja < Ninja w mojej bazie danych, przechowywany przy użyciu dziedziczenia pojedynczej tabeli. Później zdaję sobie sprawę, że naprawdę jest WaterNinja < Ninja. Jaki jest najczystszy sposób, aby zmienić go na inną podklasę? Nawet lepiej, chciałbym stworzyć nowy obiekt WaterNinja i po prostu zamienić stary FireNinja w DB, zachowując ID.Zmiana klasy obiektu w ActiveRecord

Edit wiem jak utworzyć nową WaterNinja obiektu z mojego istniejącego FireNinja, i wiem też mogę usunąć starą i zapisać nowy. To, co chciałbym zrobić, to zmutować klasę istniejącego przedmiotu. Czy to robię, tworząc nowy obiekt i wykonując trochę magii ActiveRecord, aby zastąpić wiersz, lub robiąc coś w rodzaju szaleństwa do samego obiektu, lub nawet usuwając go i wstawiając z tym samym identyfikatorem jest częścią tego pytania.

Odpowiedz

2

trzeba zrobić dwie rzeczy:

  • Tworzenie WaterNinja < Ninja
  • W ninjas tabeli uruchomić coś jak UPDATE ninjas SET (type = 'WaterNinja') WHERE (type = 'FireNinja')

to wszystko.

Za wykonanie konwersji środowiska wykonawczego będzie to możliwe, ale nie polecam.

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

Problem polega na tym, że teraz będzie @fire_ninja być wyrzucenie przedmiot.

+0

Wygląda na to, że odpowiadasz: "jak mogę przekonwertować wszystkie" FireNinjas "na" WaterNinjas "? Odpowiedź nadal działa, jeśli zmienię warunek na "ID = myid". Tak, myślałem o tym.Musiałbym również wyciągnąć obiekt po aktualizacji, aby wykonać pewne ustawienie pola specyficzne dla WaterNinja, ale to w porządku. Miałem jednak nadzieję na coś nieco czystszego. –

+0

Widzę, co masz na myśli. Nie polecam tego, ale to zadziała: 'ninja_id = @ ninja.id; @ ninja.update_attribute (: type, "WaterNinja"); @ninja = WaterNinja.find (ninja_id) ' –

+0

Edytowane, aby pokazać opisaną przeze mnie metodę. –

-1

Będziesz musiał zdefiniować metodę WaterNinja#to_fireninja. Ruby nie ma możliwości zmiany klasy obiektu przy zachowaniu tego samego obiektu.

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

To utworzy nowy obiekt, ale kiedy zadzwonię, zapiszę, utworzy on inny wiersz w bazie danych. Chcę zastąpić moją stałą instancję FireNinja moim nowym obiektem WaterNinja. –

+0

@Isaac: Nie sądzę, że jest to możliwe, chyba że możesz usunąć WaterNinja i wymusić ActiveRecord, aby zapisać nowy FireNinja z tym samym ID. – Adrian

+0

jednym ze sposobów, na które można odpowiedzieć na to pytanie, to czy możesz mi powiedzieć, jak zapisać nowego ninja z istniejącym ID. Z chęcią usunę i ponownie zainstaluję. –

0

Skład faworyzowania w przypadku dziedziczenia - należy stosować wzorzec strategii, aby zmienić ten typ zachowania w środowisku wykonawczym.

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

+0

Niekoniecznie. Google za wzorce refaktoryzacji typu "zastąp typ polimorfizmem" i "zastąp typ ze strategią". Używanie strategii obejmuje niektóre przypadki, ale w innych preferuje się dziedziczenie. Wzorce te są również opisane w książce Refactoring (http://www.amazon.com/Refactoring-Ruby-Jay-Fields/dp/0321603508). – samuil

+0

Mam dobre powody do korzystania z dziedziczenia niezależnie od problemu, który przedstawiam powyżej. Nie buduję changetypeofninja.com. –

7

można dokonać aktu FireNinja jako WaterNinja wykonując

@ninja.becomes(WaterNinja) 

Jeśli chcesz na stałe zmienić zajęcia, a potem po prostu nadpisać atrybut type.

+0

To jest właściwa odpowiedź, zaakceptowana odpowiedź nie jest tak dobra, ponieważ nie używa "staje się" – Rob

Powiązane problemy