Dodanie kolumny do istniejącej tabeli podczas migracji Railsów

340

Mam model Użytkownicy, który potrzebuje :emailkolumny (zapomniałem dodać tę kolumnę podczas początkowego rusztowania).

Otworzyłem plik migracji i dodałem t.string :email, zrobiłem rake db:migratei dostałem NoMethodError. Potem dodałem linię

add_column :users, :email, :string

znowu rake db:migrate, znowu NoMethodError. Czy brakuje mi tutaj kroku?

Edycja: oto plik migracji.

class CreateUsers < ActiveRecord::Migration  
  def self.up  
    add_column :users, :email, :string  
    create_table :users do |t|  
      t.string :username  
      t.string :email  
      t.string :crypted_password  
      t.string :password_salt  
      t.string :persistence_token  

      t.timestamps  
    end  
  end  

  def self.down  
    drop_table :users  
  end  
end
Jan
źródło

Odpowiedzi:

573

Jeśli już uruchomiłeś oryginalną migrację (przed jej edycją), musisz wygenerować nową migrację (załatwi sprawę rails generate migration add_email_to_users email:string). Utworzy plik migracji zawierający wiersz: add_column :users, email, string Następnie wykonaj a rake db:migratei uruchomi nową migrację, tworząc nową kolumnę.

Jeśli pierwotna migracja nie została jeszcze uruchomiona, możesz ją po prostu edytować, tak jak próbujesz. Twój kod migracji jest prawie idealny: wystarczy add_columncałkowicie usunąć wiersz (ten kod próbuje dodać kolumnę do tabeli, zanim tabela zostanie utworzona, a kod tworzenia tabeli został już zaktualizowany, aby i t.string :emailtak zawierał ).

Dylan Markow
źródło
6
Żeby było jasne, używamy liczby mnogiej? Więc to jest add_email_to_usersi NIE add_email_to_user?
Purplejacket
9
Poprawny. Nazwy tabel w szynach są zawsze w liczbie mnogiej (w celu dopasowania do konwencji DB).
camdez
2
Możesz także użyć rails db:migratedo ostatniego kroku.
Dylan Vander Berg,
Czy można utworzyć nową kolumnę na określonej pozycji w tabeli. Na przykład, jeśli chcę utworzyć nowy „status” pola tuż po istniejącym polu „e-mail”?
neeraj
2
@ neeraj prawdopodobnie masz już odpowiedź, ale dla innych osób poszukujących, tak, możesz np. w t.string :column_x, limit: 10, after: :column_y( np. dla Rails 4)
244
123

Użyj tego polecenia w konsoli szyn

rails generate migration add_fieldname_to_tablename fieldname:string

i

rake db:migrate

aby uruchomić tę migrację

vinodh
źródło
57

Czasami rails generate migration add_email_to_users email:stringpowoduje taką migrację

class AddEmailToUsers < ActiveRecord::Migration[5.0]
  def change
  end
end

W takim przypadku trzeba ręcznie add_columndo change:

class AddEmailToUsers < ActiveRecord::Migration[5.0]
  def change
    add_column :users, :email, :string
  end
end

A potem biegnij rake db:migrate

Apoorv Agarwal
źródło
1) Czy powinno rails generate migration add_email_to_users email:stringto być uruchamiane za bundle exec rails cterminalem czy tylko w nim? 2) Gdzie jest generowany plik umieszczony po wykonaniu zapytania?
sofs1,
28

Możesz też zrobić

rake db:rollback

jeśli nie dodałeś żadnych danych do tabel. Następnie edytuj plik migracji, dodając do niego kolumnę e-mail, a następnie zadzwoń

rake db:migrate

Działa to, jeśli w systemie są zainstalowane szyny 3.1.

Znacznie prostszym sposobem na to jest zmiana, niech zmiana w pliku migracji będzie taka, jaka jest. posługiwać się

$rake db:migrate:redo

Spowoduje to wycofanie ostatniej migracji i migrację.

Ninz
źródło
21

Aby dodać kolumnę, musiałem wykonać następujące kroki:

  1. rails generate migration add_fieldname_to_tablename fieldname:string

    Alternatywny

    rails generate migration addFieldnameToTablename

    Po wygenerowaniu migracji edytuj migrację i zdefiniuj wszystkie atrybuty, które ma mieć dodana kolumna.

    Uwaga : Nazwy tabel w szynach są zawsze w liczbie mnogiej (w celu dopasowania do konwencji DB). Przykład przy użyciu jednego z kroków wymienionych wcześniej-

    rails generate migration addEmailToUsers

  2. rake db:migrate

Lub

  1. Możesz zmienić schemat z db/schema.rb, Dodaj kolumny, które chcesz w zapytaniu SQL.
  2. Uruchom to polecenie: rake db:schema:load

    Ostrzeżenie / Uwaga

    Pamiętaj, że uruchamianie rake db:schema:loadautomatycznie usuwa wszystkie dane z twoich tabel.

Pratik Naik
źródło
Zrobiłem to, ale nie przerobiłem „rusztowania” i nie dodałem nowej kolumny. Jak mogę to zrobić „automagicznie”?
John Wooten
@John Wooten, możesz usunąć Scaffold i przejść przez to ponownie. Usuń także odpowiednie migracje.
Afolabi Olaoluwa Akinwumi,
dodać notatkę: zmiana schematu bez zmiany migracji może powodować problemy z utrzymaniem aplikacji przez innych programistów.
BKSpurgeon
3

Kiedy to zrobiłem, zamiast majstrować przy oryginalnej migracji, tworzę nową z dodaną kolumną w górnej części i kolumną upuszczającą w dolnej części.

Możesz zmienić oryginał i uruchomić go ponownie, jeśli przeprowadzasz migrację pomiędzy, ale w tym przypadku myślę, że migracja nie działa poprawnie.

W tej chwili dodajesz kolumnę, a następnie tworzysz tabelę.

Jeśli zmienisz kolejność, może to działać. Lub, gdy modyfikujesz istniejącą migrację, po prostu dodaj ją do tabeli tworzenia zamiast oddzielnej kolumny dodawania.

Don Roby
źródło
1

Możesz również wymusić na tabelach kolumny w tabeli za pomocą force: true, jeśli tabela już istnieje.

przykład :

ActiveRecord::Schema.define(version: 20080906171750) do
  create_table "authors", force: true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
  end
end
Aravin
źródło
1

Możesz również użyć specjalnej metody change_table w migracji, aby dodać nowe kolumny:

change_table(:users) do |t|
  t.column :email, :string
end
ruslanimos
źródło
0

Możesz cofnąć ostatnią migrację o

rake db:rollback STEP=1

lub przywróć tę konkretną migrację o

rake db:migrate:down VERSION=<YYYYMMDDHHMMSS>

i edytuj plik, a następnie uruchom rake db:mirgateponownie.

Fangxing
źródło
0

Możesz także dodać kolumnę do określonej pozycji za pomocą przed kolumną lub po kolumnie, np .:

rails generate migration add_dob_to_customer dob:date

Plik migracji wygeneruje następujący kod, z wyjątkiem:: e-mail. musisz dodać po:: email lub przed:: email

class AddDobToCustomer < ActiveRecord::Migration[5.2]
  def change
    add_column :customers, :dob, :date, after: :email
  end
end
Khabir
źródło