Odpowiedzi:
Pomocnik znacznika czasu jest dostępny tylko w create_tablebloku. Możesz dodać te kolumny, określając typy kolumn ręcznie:
class AddTimestampsToUser < ActiveRecord::Migration
def change_table
add_column :users, :created_at, :datetime, null: false
add_column :users, :updated_at, :datetime, null: false
end
end
Chociaż nie ma tej samej zwięzłej składni, co add_timestampsmetoda, którą określiłeś powyżej, Railsy nadal będą traktować te kolumny jako kolumny ze znacznikami czasu i normalnie aktualizować wartości.
rails g migration AddTimestampsToUser created_at:datetime updated_at:datetime- skrót do wygenerowania migracji powyżej.
PG::NotNullViolation: ERROR: column "created_at" contains null value ponieważ moja tabela zawiera już dane, które naruszają ograniczenie niepuste. Czy jest jakiś lepszy sposób na zrobienie tego niż najpierw usunięcie niezerowego ograniczenia, a następnie dodanie go później?
add_column :users, :updated_at, :datetime, null: false, default: Time.zone.now. Time.zone.nowto tylko przykład, powinieneś użyć dowolnej wartości, która ma sens dla twojej logiki.
Migracje to tylko dwie metody klas (lub metody instancji w 3.1): upi down(a czasami changemetoda instancji w 3.1). Chcesz, aby zmiany zostały wprowadzone do upmetody:
class AddTimestampsToUser < ActiveRecord::Migration
def self.up # Or `def up` in 3.1
change_table :users do |t|
t.timestamps
end
end
def self.down # Or `def down` in 3.1
remove_column :users, :created_at
remove_column :users, :updated_at
end
end
Jeśli jesteś w wersji 3.1, możesz również użyć change(dzięki Dave):
class AddTimestampsToUser < ActiveRecord::Migration
def change
change_table(:users) { |t| t.timestamps }
end
end
Być może jesteś mylące def change, def change_tablei change_table.
Więcej informacji zawiera przewodnik migracji .
changemetoda, chociaż w tym przypadku nie problem :)
changewarto o tym wspomnieć, więc też to dodam.
Twój oryginalny kod jest bardzo zbliżony do właściwego, wystarczy użyć innej nazwy metody. Jeśli używasz Railsów 3.1 lub nowszych, musisz zdefiniować changemetodę zamiast change_table:
class AddTimestampsToUser < ActiveRecord::Migration
def change
add_timestamps(:users)
end
end
Jeśli używasz starszej wersji, musisz zdefiniować upi downmetody zamiast change_table:
class AddTimestampsToUser < ActiveRecord::Migration
def up
add_timestamps(:users)
end
def down
remove_timestamps(:users)
end
end
@ user1899434 odpowiedział na fakt, że „istniejąca” tabela może oznaczać tabelę z już zawartymi rekordami, których możesz nie chcieć usunąć. Dlatego po dodaniu znaczników czasu z wartością null: false, która jest wartością domyślną i często pożądaną, wszystkie istniejące rekordy są nieprawidłowe.
Ale myślę, że odpowiedź można poprawić, łącząc dwa kroki w jedną migrację, a także używając bardziej semantycznej metody add_timestamps:
def change
add_timestamps :projects, default: Time.zone.now
change_column_default :projects, :created_at, nil
change_column_default :projects, :updated_at, nil
end
Możesz zastąpić inną sygnaturę czasową DateTime.now, na przykład gdybyś chciał zamiast tego utworzyć / zaktualizować istniejące wcześniej rekordy.
Time.zone.nowtego należy użyć, jeśli chcemy, aby nasz kod działał zgodnie z właściwą strefą czasową.
Time.zone.nowktóra polega na zwróceniu instancji Time, która jest tworzona podczas uruchamiania migracji, i po prostu używa tego czasu jako domyślnego. Nowe obiekty nie otrzymają nowej instancji Time.
class AddTimestampsToUser < ActiveRecord::Migration
def change
change_table :users do |t|
t.timestamps
end
end
end
Dostępne są transformacje
change_table :table do |t|
t.column
t.index
t.timestamps
t.change
t.change_default
t.rename
t.references
t.belongs_to
t.string
t.text
t.integer
t.float
t.decimal
t.datetime
t.timestamp
t.time
t.date
t.binary
t.boolean
t.remove
t.remove_references
t.remove_belongs_to
t.remove_index
t.remove_timestamps
end
http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html
Odpowiedź Nicka Daviesa jest najbardziej kompletna pod względem dodawania kolumn sygnatur czasowych do tabeli z istniejącymi danymi. Jedynym minusem jest to, że wzrośnie ActiveRecord::IrreversibleMigrationnadb:rollback .
Należy go tak zmodyfikować, aby działał w obu kierunkach:
def change
add_timestamps :campaigns, default: DateTime.now
change_column_default :campaigns, :created_at, from: DateTime.now, to: nil
change_column_default :campaigns, :updated_at, from: DateTime.now, to: nil
end
change_column_defaultnie obsługuje fromiw totej wersji?), Ale wziąłem ten pomysł i stworzyłem up/downmetody zamiast jednej changemetody i działało to jak urok!
def change
add_timestamps :table_name
end
nie jestem pewien, kiedy dokładnie to zostało wprowadzone, ale w railsach 5.2.1 możesz to zrobić:
class AddTimestampsToMyTable < ActiveRecord::Migration[5.2]
def change
add_timestamps :my_table
end
end
aby uzyskać więcej informacji, zobacz „ Korzystanie z metody zmiany ” w dokumentacji migracji aktywnych rekordów.
, null: truepo:my_table
Zrobiłem prostą funkcję, że można zadzwonić, aby dodać do każdej tabeli (zakładając, że masz istniejącej bazy danych) created_at i updated_at dziedzinach:
# add created_at and updated_at to each table found.
def add_datetime
tables = ActiveRecord::Base.connection.tables
tables.each do |t|
ActiveRecord::Base.connection.add_timestamps t
end
end
add_timestamps (nazwa_tabeli, opcje = {}) public
Dodaje kolumny sygnatur czasowych (created_at i updated_at) do table_name. Dodatkowe opcje (takie jak null: false) są przekazywane do #add_column.
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps(:users, null: false)
end
end
Odpowiedzi podane wcześniej wydają się prawidłowe, jednak napotkałem problemy, jeśli moja tabela zawiera już wpisy.
Otrzymałbym „BŁĄD: kolumna created_atzawiera nullwartości”.
Aby naprawić, użyłem:
def up
add_column :projects, :created_at, :datetime, default: nil, null: false
add_column :projects, :updated_at, :datetime, default: nil, null: false
end
Następnie użyłem gem migracji_data, aby dodać czas dla bieżących projektów migracji, takich jak:
def data
Project.update_all created_at: Time.now
end
Wtedy wszystkie projekty utworzone po tej migracji zostaną poprawnie zaktualizowane. Upewnij się, że serwer również został zrestartowany, aby Railsy ActiveRecordzaczęły śledzić sygnatury czasowe w rekordzie.
Wiele odpowiedzi tutaj, ale swoją też opublikuję, ponieważ żadna z poprzednich naprawdę nie zadziałała :)
Jak niektórzy zauważyli, #add_timestampsniestety dodaje null: falseograniczenie, co spowoduje, że stare wiersze będą nieprawidłowe, ponieważ nie zawierają tych wartości. Większość odpowiedzi sugeruje, że ustawiliśmy jakąś domyślną wartość ( Time.zone.now), ale nie chciałbym tego robić, ponieważ te domyślne znaczniki czasu dla starych danych nie będą poprawne. Nie widzę wartości dodawania nieprawidłowych danych do tabeli.
Więc moja migracja była po prostu:
class AddTimestampsToUser < ActiveRecord::Migration
def change_table
add_column :projects, :created_at, :datetime
add_column :projects, :updated_at, :datetime
end
end
Nie null: false, żadnych innych ograniczeń. Stare wiersze będą nadal obowiązywały z created_atas NULLi update_atas NULL(do czasu wykonania aktualizacji wiersza). Nowe wiersze będą miały created_ati updated_atwypełnione zgodnie z oczekiwaniami.
Problem z większością odpowiedzi tutaj polega na tym, że jeśli domyślnie Time.zone.nowwszystkie rekordy będą miały czas uruchomienia migracji jako domyślny czas, co prawdopodobnie nie jest tym, czego chcesz. W szynach 5 możesz zamiast tego użyć now(). Spowoduje to ustawienie sygnatur czasowych dla istniejących rekordów jako czasu uruchomienia migracji i jako czasu rozpoczęcia transakcji zatwierdzania dla nowo wstawianych rekordów.
class AddTimestampsToUsers < ActiveRecord::Migration
def change
add_timestamps :users, default: -> { 'now()' }, null: false
end
end
Używanie Time.currentto dobry styl https://github.com/rubocop-hq/rails-style-guide#timenow
def change
change_table :users do |t|
t.timestamps default: Time.current
t.change_default :created_at, from: Time.current, to: nil
t.change_default :updated_at, from: Time.current, to: nil
end
end
lub
def change
add_timestamps :users, default: Time.current
change_column_default :users, :created_at, from: Time.current, to: nil
change_column_default :users, :updated_at, from: Time.current, to: nil
end
To proste, aby dodać znacznik czasu do istniejącej tabeli.
class AddTimeStampToCustomFieldMeatadata < ActiveRecord::Migration
def change
add_timestamps :custom_field_metadata
end
end
Wydaje się, że to czyste rozwiązanie w Railsach 5.0.7 (odkryłem metodę change_column_null):
def change
add_timestamps :candidate_offices, default: nil, null: true
change_column_null(:candidate_offices, :created_at, false, Time.zone.now)
change_column_null(:candidate_offices, :created_at, false, Time.zone.now)
end
Jestem na szynach 5.0 i żadna z tych opcji nie działała.
Jedyną rzeczą, która działała, było użycie typu: timestamp, a nie: datetime
def change
add_column :users, :created_at, :timestamp
add_column :users, :updated_at, :timestamp
end
Napotkałem ten sam problem na Rails 5, próbując użyć
change_table :my_table do |t|
t.timestamps
end
Udało mi się ręcznie dodać kolumny sygnatur czasowych za pomocą następujących elementów:
change_table :my_table do |t|
t.datetime :created_at, null: false, default: DateTime.now
t.datetime :updated_at, null: false, default: DateTime.now
end