Witam,
spotkałem się ostatnio z dziwną sytuacją, że operacja wykonywała się, jeżeli była w jednej migracji. Natomiast jeżeli zmiana została rozłożona z jakiegoś powodu na dwie migracje, to niestety już druga się nie wykonywała:
[code=“ruby”]#poprawnie wykonująca się migracja:
class AddTicketTypeToCategories < ActiveRecord::Migration
def self.up
add_column :categories, :ticket_type, :string
Category.reset_column_information
Category.all.each { |cat| cat.update_attribute :ticket_type, “ticket” }
end
def self.down
remove_column :categories, :ticket_type
end
end
#migracje, z których druga nie umieszczała danych w bazie
class AddTicketTypeToCategories < ActiveRecord::Migration
def self.up
add_column :categories, :ticket_type, :string
end
def self.down
remove_column :categories, :ticket_type
end
end
class AddTicketTypesToDevData < ActiveRecord::Migration
def self.up
Category.all.each { |cat| cat.update_attribute :ticket_type, “ticket” }
end
def self.down
Category.all.each { |cat| cat.update_attribute :ticket_type, NULL }
end
end[/code]
Nie jest to pierwsza sytuacja, w której z czymś takim się spotykam i zastanawiam się, czy to jest mój jakiś błąd, czy taki ficzer Railsów…
Pozdrawiam,
Yax
Rails poprostu nie przeladowuje srodowiska miedzy migracjami, wiec nowe kolumny sa nie widoczne.
Polecam albo dodanie reset_column_infomation albo uzywanie metod ktore nie lukaja po atrybutch, tutaj z powodzeniem mozesz uzyc Category.update_all([‘ticket_type = ?’, ‘ticket’]).
Chyba nie do końca tak jest. Gdyby tak było to #update_attribute powinien rzucić wyjątkiem. reset_column_information było wymagane bodajże przed 1.2.6 teraz imho nie jest w takich wypadkach.
def self.down
remove_column :categories, :ticket_type
end
end[/code]
Nie dostaniesz wyjatku, tylko ticket_type nie zostanie zaktualizowane. Wiec reset_column_information jest nadal wymagane.
Tzn, zadziałało reset_column_information po wrzuceniu do drugiej migracji. A w jednej migracji jest wymagane, jeżeli chce się dodać dane. W dokumentacji bieżącej jest o tym mowa.
Modyfikacja treści bazy danych nie jest dobrym pomysłem w migracjach.
Migracje powinny operować jedynie na schemacie bazy danych. Migracje NIE SĄ dobrym miejscem do tworzenia, usuwania czy modyfikowania rekordów, i to z różnych powodów.
W rails 3 jest bootstrapping, który jednak w rails 2.3 możesz sobie śmiało zastąpić taskiem rake i tam wykonywać operacje na bazie.
Jeszcze raz, cobyś zapamiętał:
MIGRACJE NIE SĄ DOBRYM MIEJSCEM DO MODYFIKACJI TREŚCI BAZY DANYCH.
A co w przypadku np. zmiany typu kolumny / dodania nowej kolumny która trzeba zainicjować domyślną wartością generowaną na podstawie dynamicznych informacji? Ja bym to robił w migracji.Szczególnie przy modyfikowaniu bazy produkcyjnej - dzieki temu mozna sie wycofać.
Na przykład dodaję nowe pole, które musi być wypełnione wartościami, które zależą od innych pól modelu. Przy tworzeniu nowych obiektów pole to zostanie wypełnione, ale co z obecną bazą danych? Najłatwiej to zrobić migracji.
@hubertlepicki
Tak, wiem, że w migracjach nie powinno się modyfikować danych, ale to są tylko moje dane żebym coś miał w bazie przy pisaniu aplikacji. Nie odniosę się do zmiany w ten sposób danych w bazie produkcyjnej, bo nigdy jeszcze takowej nie miałem
@morgoth
Ciekawa sprawa, choć te dane o których w moich migracjach mowa, to nie są wartości domyślne, tylko dane, żebym miał co klikać.
Nie lepiej, skoro robisz to na developmencie, po prostu machnąć mikroskrypt i nie zatruwać migracji (które potem pójdą przecież na produkcji) tego typu kodem?
Fajnie że seedy zostały backportowane do 2.3.4, już myślałem że trzeba będzie na 3.0 czekać
Dokładnie, też się tego nie spodziewałem i dowiedziałem się z tego wątku :).
Osobiście znam jednago gagatka który nie tylko modyfikuje treść bazy z migracji, twierdzi również że najlepszym sposobem na tworzenie bazy w production jest użycie “rake db:reset” ;D. No jasne że jest, kiedy migracje nie chcą się zapuścić od v0 do ostatniej ;).