Dodanie kolumny do tabeli

Witam,

użyłem migracji do wygenerowania tabeli. Teraz chce dodać jeszcze jedną kolumnę:

def self.up create_table :users do |t| t.column :email, :string end add_column :name, :string end
Uruchamiam migrację i nic. Więc jak za pomocą migracji dodać dodatkowe kolumny ?

Pozdrawiam

Brakuje Ci jednego parametru, nazwy tabeli.

add_column :name, :string

zamień na add_column :users, :name, :string
Ale w praktyce najłatwiej zrobić to tak

# script/generate migration add_email_to_user email:string

zobacz sam, co tak naprawdę się wygeneruje w takiej migracji, to samo można zrobić ręcznie.

A swoją drogą zapoznaj się z dokumentacją do migracji, np tu:
http://api.rubyonrails.org/classes/ActiveRecord/Migration.html

Masz dwie opcje. Pierwsza to utworzyć nową migrację i w niej dodać tą kolumnę:

ruby script/generate migration add_new_column_to_some_table

[code=ruby]class AddColumnToSomeTable.rb < ActiveRecord::Migration
def self.up
add_column :some_table, :column_name, :integer
end

def self.down
remove_column :some_table, :column_name
end
end[/code]
Druga opcja to cofnięcie migracji do poprzedzającej tą którą chcesz edytować (rake db:migrate VERSION=N), następie przeedytowaie jej i odpalenie. Jednak jeśli pracujesz w grupie i np używasz svn a ta migracja “poszła w świat” to lepsza jest pierwsza opcja.

Wróciłem do poprzedniej wersji migracji. Czy generowanie migracji tylko po to, żeby dodać jedną kolumnę w tabeli nie zaśmieca projektu ? Wyobrażam sobie np takich 15 operacji co się równa dodatkowej ilości plików ?

Nie zaśmieca. To railsy biorą na siebie odpalenie migracji w odpowiedniej kolejności i sprawdzenie jaka aktualnie jest wersja. Ty jako developer tylko je dodajesz. Nie widzę tu zaśmiecania :).

W przypadku produkcji zgadzam się z tym, co wyżej napisał Radarek, ale osobiście, gdy developuję nowe rozwiązanie, po prostu edytuję źródłowe migracje i odpalam co jakiś czas

[code]# rake db:migrate VERSION=0

rake db:migrate[/code]

Gdzie 0 jest jakąś wersją migracji która jeszcze nic nie zmienia. Nowe migracje typu dodawanie kolumny tworzę dopiero, gdy system wejdzie na produkcję, czy zaawansowane testy. Po prostu nie widzę potrzeby tworzenia nowej migracji dopóki nie jest potrzebna migracja, bo nie ma istniejących danych.

bumelant, zgodzę się, ale tylko w przypadku jeśli jeszcze nie wysłałeś danej migracji do repozytorium (zakładam że jest używane). Takie edytowanie wstecz prawdopodobnie nie zostanie zauważone przez programistów.

Użycie VCS i dużej liczby migracji bywa takim samym proszeniem się o kłopoty, gdy migracje później konfliktują numerem wersji i robią różne rzeczy na tych samych tabelach. Nie wydaje mi się, żeby migracje coś ułatwiały w tej kwestii, raczej to rozwiązanie z diff na pliku tworzącym tabele wydaje mi się bardziej naturalne i tracimy go na rzecz ułatwień z przenoszeniem zmian na produkcję.

Według mnie zauważenie zmian przez programistę, to bardziej kwestia umowy między programistami i tego, żeby modelować modele wspólnie, a nie tego, czy ktoś przeczyta o migracji w commitlogu, który dostanie na maila, czy zrobi ls db/migrate, bo w nawale pracy ani jednego ani drugiego może nie zrobić wcale :slight_smile:

Od dłuższego czasu istnieje już plugin numerujący migracje według timestampów, w Rails Edge jest już (czyli będzie w 2.1) numerowanie migracji według czasu UTC (YYYY-MM-DD_hhmm bodajże).

[quote=bumelant]Użycie VCS i dużej liczby migracji bywa takim samym proszeniem się o kłopoty, gdy migracje później konfliktują numerem wersji i robią różne rzeczy na tych samych tabelach. Nie wydaje mi się, żeby migracje coś ułatwiały w tej kwestii, raczej to rozwiązanie z diff na pliku tworzącym tabele wydaje mi się bardziej naturalne i tracimy go na rzecz ułatwień z przenoszeniem zmian na produkcję.

Według mnie zauważenie zmian przez programistę, to bardziej kwestia umowy między programistami i tego, żeby modelować modele wspólnie, a nie tego, czy ktoś przeczyta o migracji w commitlogu, który dostanie na maila, czy zrobi ls db/migrate, bo w nawale pracy ani jednego ani drugiego może nie zrobić wcale :)[/quote]
Migracje wymagają pewnego zrozumienia. Jeśli ktoś myśli, że zawsze i wszędzie zadziałają zgodnie z oczekiwaniami to jest w błędzie. Modelowanie bazy także nie powinno wyglądać tak, że każdy z członków teamu kiedy chce dodaje sobie coś do bazy. Jakieś zasady muszą jednak panować.

Pracowałem kiedyś przy projekcie gdzie było 4 programistów php. Każdy mógł zmienić bazę, a robiło się to poprzez dodanie instrukcji SQL we wspólnym pliku .sql. Powiem tylko tak: było to przeogromnie niewygodne rozwiązanie. Migracje przy tym to jest bajka, ale tak jak mówię: trzeba dobrze wiedzieć jak ich używać (konflikty numeryczne mogą się zdarzyć, nowe migracje oparte na timestampach powinny to poprawić).

Możesz rozwinąć myśl ?

2+ programistów ma na swoich maszynach bazę w “wersji” 44, każdy z nich potrzebuje dodać sobie pole - każdy inne w innej tabeli. Każdy więc tworzy “swoją” migrację o numerze 45. Kiedy każdy z nich wrzuci swój plik “45” do repozytorium i zassie pliki pozostałych, mamy mocnego blokera: skrypt robiący migrację u żadnego z nich nie wykona zmian dorzuconych przez pozostałych, bo baza już przecież jest w wersji 45. Zmiana nazw pliku (każdy sobie - koszmar!) pomoże tylko doraźnie - migracje kolegów się wykonają, ale potem znowu są jaja w repozytorium. Autor migracji 045_add_field_one będzie miał plik 046_add_table_two i taki dorzuci repo, natomiast autor migracji 045_add_table_two dorzuci do repo plik 046_add_field_one. Nagle z (logicznie) dwóch migracji mamy w repozytorium cztery pliki i bajzel.

W skrócie, jeśli ktoś zgubił wątek w poprzednim akapicie: będzie chaos i burdel :wink:

Chodzi o prostą sytuację gdy 2 programistów niezależnie tworzy nową migracje. Chociaż będą to dwie różne migracje to otrzymają ten sam numer. Programista A odpali u siebie swoją migrację, programista B z kolei swoją. Potem obaj zacommitują zmiany i zrobię update. Następny rake db:migrate nic nie zrobi bo obaj mają odpalone migracje o największym numerze.

W praktyce każdy programista przed commitem powinien zrobić update i sprawdzić czy inny programista dodał jakieś migracje. Jeśli tak to powinien przenumerować swoje (podkreślam to bo już mi qmpel potrafił przenumerować tak że nie wiedziałem co się dzieje) migracje i dopiero zrobić commit (poprzedzony updatem aż do momentu, w którym nie ma zmian w migracjach).

Jakby co to za długo zajmowałem się czymś innym podczas gdy formularz z wypełnioną treścią nie był wysłany (jakby ktoś się zdziwił czemu napisałem prawie to samo co @Tomash).

Jasne, migracje to jest świetny pomysł, chętnie przeniósłbym go w niezarubione obszary. Najlepszą ideą w migracjach jest fakt, że migracje są zwykłym plikiem rubyego - można dzięki temu zrobić tam wszystko niezależnie od enginu bazy.

Kiedyś miałem do czynienia z czymś takim, jak skrypty migracyjne, które same robiły dużego diffa między schematami typu development -> produkcja, ale już wyliczenie dodatkowych danych dla jakiejś tabeli, które w Rails robi migracja w Rubym, eksportowało się tzw. raportem. Taki raport, na ogół będący jakimś ciągiem (PL/)SQLa, de facto jest po prostu migracją z Rubyego, tylko że rolę db:migrate pełniła osoba w Agile nazywana DBA, czyli taki bardziej świadomy adminstrator, a reszta dzieje się magicznie.

Jakoś to działało, ale w porównaniu z migracjami to po prostu koszmar i wymagał zatrunienia jednej osoby więcej :slight_smile: - nie żeby DBA był nie dobrą praktyką, ale nie zawsze możliwą do zrealizowania. Do tej pory w małych projektach, gdzie nie było nawet mocy produkcyjnych, a co dopiero DBA, też używałem pliku schemy, też robiłem ten błąd, że jednego.

A że do numerowania istnieją pluginy i zadania rake, to wiem, że będzie nowa generacja migracji nie wiedziałem, dzięki za info, ale tak generalnie - nic nie stoi na przeszkodzie nawet w rozproszonych projektach puścić maila typu “biorę 48”, w końcu w Rails nie piszemy jeszcze centralnych systemów ERP (a szkoda :)). Po prostu wydaje mi się, ale być może to zależy od stylu pracy, że z punktu widzenia współpracy, zysk jest dyskusyjny.