2009-10-16 9 views
78

consideri lo script di creazione tabella:Come impostare il valore predefinito per una colonna datetime nello script di migrazione?

create_table :foo do |t| 
    t.datetime :starts_at, :null => false 
end 

E 'possibile impostare il valore di default come il tempo attuale?

Sto cercando di trovare un DB equivalente indipendente sulle rotaie per le definizioni di colonna SQL di seguito riportate:

sintassi Oracle

start_at DATE DEFAULT SYSDATE() 

sintassi MySQL

start_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 

O

start_at DATETIME DEFAULT NOW() 

risposta

109

È possibile aggiungere una funzione in un modello come questo:

before_create :set_foo_to_now 
    def set_foo_to_now 
    self.foo = Time.now 
    end 

modo che il modello verrà impostata l'ora corrente nel modello.

Si può anche mettere un po 'di codice SQL nella migrazione per impostare il valore di default a livello di database, qualcosa di simile:

execute 'alter table foo alter column starts_at set default now()' 

impostazione qualcosa di simile:

create_table :foo do |t| 
    t.datetime :starts_at, :null => false, :default => Time.now 
end 

cause esecuzione del Tempo .now durante la migrazione, quindi la tabella nel database viene creata in questo modo:

create table foo (starts_at timestamp not null default '2009-01-01 00:00:00'); 

ma penso che non è quello che vuoi.

+1

Attualmente sto impostando il valore nel: before_create callback.
Stavo cercando un tipo di magia AR qui. Ho passato un po 'di tempo a guardare il codice Rails, ma non ho trovato alcuna soluzione. Ho pensato di chiedere in giro per vedere se ci sono alternative. –

+0

Suggerirei di farlo con un callback su before_create. – jonnii

+1

Non voglio modificare la tabella DB perché voglio mantenere neutro il mio codice DB. Speravo che AR avesse qualche meccanismo per impostare il valore predefinito per il campo Datetime simile al campo created_at. –

12

Se si dispone di una colonna datetime denominata created_at o created_on, ActiveRecord "magicamente" lo imposterà sulla data/ora di creazione. Non devi fare nient'altro se non quello di avere quella colonna.

È inoltre possibile avere updated_at o updated_on e verrà aggiornato quando un record viene aggiornato.

+0

Ho già quei campi nella mia tabella. Ho bisogno di un campo aggiuntivo per il mio scheduler per contenere la data di inizio. Attualmente sto usando: before_create callback per impostare la data corrente. Se incontro spesso questo scenario, devo ricorrere alla scrittura di un plugin per modificare la gestione dei valori di default nel metodo 'to_sql' della classe ColumnDefinition. –

9

Ero alla ricerca di una soluzione simile ma ho finito con https://github.com/FooBarWidget/default_value_for.

Il plug-in default_value_for consente di definire i valori predefiniti per i modelli ActiveRecord in modo dichiarativo. Per esempio:

class User < ActiveRecord::Base 
    default_value_for :name, "(no name)" 
    default_value_for :last_seen do 
    Time.now 
    end 
end 

u = User.new 
u.name  # => "(no name)" 
u.last_seen # => Mon Sep 22 17:28:38 +0200 2008 
-1

Nella risposta data dal @ Szymon-Lipiński (Szymon Lipiński), il metodo di esecuzione non ha funzionato per me. Stava generando un errore di sintassi MySQL.

La sintassi MySQL che ha funzionato per me è questa.

execute "ALTER TABLE mytable CHANGE `column_name` `column_name` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP" 

Quindi, per impostare il valore predefinito per una colonna datetime in script di migrazione può essere fatto nel modo seguente:

def up 
    create_table :foo do |t| 
    t.datetime :starts_at, :null => false 
    end 

    execute "ALTER TABLE `foo` CHANGE `starts_at` `starts_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP" 
end 
7

faccio di solito:

def change 
    execute(" 
    ALTER TABLE your_table 
    ALTER COLUMN your_column 
    SET DEFAULT CURRENT_TIMESTAMP 
    ") 
end 

Così, il vostro schema.rb sta andando per avere qualcosa come:

create_table "your_table", force: :cascade do |t| 
    t.datetime "your_column", default: "now()" 
end 
+0

Il lato negativo: questa soluzione funziona solo quando si esegue 'rake db: migrate', non quando si carica il file di schema con qualcosa come' rake db: schema: load'. –

82

Questo è supportato ora in Rails 5.

Ecco una migrazione di esempio:

class CreatePosts < ActiveRecord::Migration[5.0] 
    def change 
    create_table :posts do |t| 
     t.datetime :modified_at, default: -> { 'CURRENT_TIMESTAMP' } 
     t.timestamps 
    end 
    end 
end 

See discussione al https://github.com/rails/rails/issues/27077 e rispondere lì da Prathamesh-sonpatki

+6

+10000 questa è la risposta più pertinente al giorno d'oggi. – hcarreras

+5

Ottima risposta. Puramente a parte, sappi che in Postgres 'CURRENT_TIMESTAMP' sarà il momento dell'inizio della transazione corrente, quindi più record creati nella stessa transazione avranno lo stesso valore. Se vuoi che l'attuale ora corrente venga eseguita dall'istruzione (ignorando il contesto della transazione), controlla "CLOCK_TIMESTAMP". –

-1

Se è necessario cambiamento un colonna DateTime esistente in Rails 5 (anziché creare una nuova tabella come specificato in altre risposte) in modo che possa sfruttare la funzionalità di data predefinita, è possibile creare una migrazione come questa:

class MakeStartsAtDefaultDateForFoo < ActiveRecord::Migration[5.0] 
    def change 
    change_column :foos, :starts_at, :datetime, default: -> { 'CURRENT_TIMESTAMP' } 
    end 
end 
+0

Cattivo modulo per votare qualcosa e non spiegare quale problema è stato preso con la risposta. Qualcuno ha un'idea del motivo per cui è stato votato? Sta visualizzando la sintassi se si desidera modificare una colonna invece di crearne una. –

+0

Non sono io quello che ha downvoted, ma ho difficoltà a vedere come questa risposta differisce dalla risposta di Will che precede la tua di un anno.La domanda riguarda l'impostazione di un valore predefinito e la tua risposta ha la stessa clausola lambda. – nurettin

+0

@nurettin Ricevo il tuo punto, ma a mia difesa, la sintassi per ** la creazione di ** una nuova colonna è leggermente diversa da ** cambiando ** una colonna esistente. Fornire che la sintassi per coloro che hanno trovato questa domanda tramite la ricerca sul Web mentre si tenta di aggiungere un valore predefinito al proprio modello di dati corrente piuttosto che creare un nuovo modello/tabella è probabilmente piuttosto utile. No? Stai assumendo che tutti sappiano che possono usare lo stesso lambda per una change_column. Forse dovrebbero rendersene conto, ma è per questo che ho risposto qui - quindi non devono andare da nessun'altra parte per capirlo. Saluti! –

Problemi correlati