2009-10-16 16 views
78

Considere el script de creación de tabla:¿Cómo establecer el valor predeterminado para una columna de fecha y hora en el script de migración?

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

¿Es posible establecer el valor por defecto como el tiempo actual?

Estoy tratando de encontrar un equivalente independiente DB en los carriles para las definiciones de columna de SQL se indican a continuación:

Oracle Sintaxis

start_at DATE DEFAULT SYSDATE() 

MySQL Sintaxis

start_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP 

O

start_at DATETIME DEFAULT NOW() 

Respuesta

109

Usted puede agregar una función en un modelo como este:

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

para que el modelo se ajustará la hora actual en el modelo.

También puede colocar un poco de código SQL en la migración para establecer el valor por defecto en el nivel de base de datos, algo así como:

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

Configuración de algo como esto:

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

causas ejecutando el tiempo .now función durante la migración por lo que la tabla en la base de datos se crea así:

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

pero creo que no es lo que quieres.

+1

Actualmente estoy estableciendo el valor en la devolución de llamada: before_create.
Estaba buscando algún tipo de magia AR aquí. Pasé un tiempo mirando el código de Rails, pero no encontré ninguna solución. Pensé en preguntar por si había alguna alternativa. –

+0

Sugeriría hacerlo con una devolución de llamada en before_create. – jonnii

+1

No quiero alterar la tabla DB porque quiero mantener mi código DB neutral. Esperaba que AR tuviera algún mecanismo para establecer el valor predeterminado para el campo Fecha y hora similar al campo created_at. –

12

Si tiene una columna de fecha y hora llamada created_at o created_on, ActiveRecord lo establecerá "mágicamente" en la fecha de creación. No necesita hacer nada más excepto tener esa columna.

También puede tener updated_at o updated_on y se actualizará cuando se actualice un registro.

+0

Ya tengo esos campos en mi tabla. Necesito un campo adicional para que mi planificador tenga la fecha de inicio. Actualmente, estoy usando: before_create callback para establecer la fecha actual. Si encuentro este escenario con frecuencia, tengo que recurrir a escribir un complemento para alterar el manejo del valor predeterminado en el método 'to_sql' de la clase ColumnDefinition. –

9

Estaba buscando soluciones similares pero terminé usando https://github.com/FooBarWidget/default_value_for.

El complemento default_value_for permite definir valores predeterminados para los modelos ActiveRecord de manera declarativa. Por ejemplo:

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

En la respuesta dada por @ Szymon-Lipiński (Szymon Lipiński), el método de ejecución no funcionó para mí. Estaba arrojando un error de sintaxis MySQL.

La sintaxis de MySQL que funcionó para mí es esta.

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

Así que para establecer el valor predeterminado para una columna de fecha y hora en el script de migración se puede hacer de la siguiente manera:

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

que suelo hacer:

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

lo tanto, su schema.rb va tener algo como:

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

La desventaja: esta solución sólo funciona cuando se ejecuta 'rake db: migrate', no cuando se carga el archivo de esquema con algo como' rake db: schema: load'. –

82

Esto es apoyado ahora en Rails 5.

Aquí es una muestra de la migración:

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 

Véase la discusión en https://github.com/rails/rails/issues/27077 y responder allí por prathamesh-sonpatki

+6

+10000 esta es la respuesta más relevante hoy en día. – hcarreras

+5

Gran respuesta. Puramente como un aparte, tenga en cuenta que en Postgres 'CURRENT_TIMESTAMP' será la hora del inicio de la transacción actual, por lo que los registros múltiples creados en la misma transacción obtendrán el mismo valor. Si desea la hora actual real que ejecuta la instrucción (ignorando el contexto de transacción), revise 'CLOCK_TIMESTAMP'. –

-1

Si necesita cambio una columna DateTime existente en los carriles 5 (en lugar de crear una nueva tabla como se especifica en otras respuestas) para que se pueda aprovechar la capacidad de fecha por defecto, puede crear una migración de esta manera:

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

Mala forma de votar algo y no explicar qué problema se tomó con la respuesta. ¿Alguien tiene una idea de por qué esto fue rechazado? Está mostrando la sintaxis si quería cambiar una columna en lugar de crear una. –

+0

No soy el que menos votó, pero estoy teniendo dificultades para ver cómo esta respuesta difiere de la respuesta de la voluntad que precede a la suya por un año.La pregunta es sobre establecer un valor predeterminado, y su respuesta tiene la misma cláusula lambda. – nurettin

+0

@nurettin Entiendo tu punto, pero en mi defensa, la sintaxis para ** crear ** una nueva columna es sutilmente diferente de ** cambiar ** una columna existente. Proporcionar esa sintaxis para aquellos que encontraron esta pregunta a través de la búsqueda web al intentar agregar un valor predeterminado a su modelo de datos actual en lugar de crear un nuevo modelo/tabla es probablemente bastante útil. ¿No? Estás asumiendo que todos saben que pueden usar el mismo lambda para una change_column. Tal vez deberían darse cuenta de eso, pero es por eso que respondí aquí, así que no tienen que ir a ningún otro lado para darse cuenta de eso. ¡Aclamaciones! –

Cuestiones relacionadas