2009-05-14 21 views
54

Si tiene columnas DB created_at y updated_at, Rails establecerá automáticamente esos valores cuando cree y actualice un objeto modelo. ¿Hay alguna manera de guardar el modelo sin tocar esas columnas?¿Hay alguna manera de evitar actualizar automáticamente los campos de marca de tiempo de Rails?

Traigo algunos datos legados y me gustaría establecer esos valores a partir de los valores correspondientes en los campos de datos legados (con nombres diferentes). Estoy descubriendo que cuando los configuro en el modelo y luego guardo el modelo, Rails parece anular los valores entrantes.

Por supuesto, podría nombrar las columnas del modelo de Rails de manera diferente para evitar eso, pero después de que se importen los datos, quiero que Rails haga su marca de fecha y hora automática.

Respuesta

66

hacer esto de una migración o en una tarea rake (o en the new database seeds si estás en canales del borde):

ActiveRecord::Base.record_timestamps = false 
begin 
    run_the_code_that_imports_the_data 
ensure 
    ActiveRecord::Base.record_timestamps = true # don't forget to enable it again! 
end 

Se puede establecer con seguridad created_at y updated_at manualmente, rieles no se quejará .

Nota: Esto también funciona en modelos individuales, p. User.record_timestamps = false

+3

Incluso puede aplicar esto en un método, p. 'def without_timestamps edad = ActiveRecord :: Base.record_timestamps ActiveRecord :: Base.record_timestamps = false comenzar rendimiento garantizar ActiveRecord :: Base.record_timestamps = old end end' – nonrectangular

+1

¿Necesitamos restablecerlo de nuevo a 'true' incluso al ejecutar scripts o código dentro de la consola? – oldergod

+2

Creo que http://stackoverflow.com/a/37193298/1214748 es mucho mejor. No se apaga de forma global para toda la aplicación – maschwenk

28

Puede establecer la siguiente dentro de la migración:

ActiveRecord::Base.record_timestamps = false 

O altenatively utilizar update_all:

update_all (actualizaciones, condiciones = nil, opciones = {})

Actualiza todos los registros con detalles dados si coinciden con un conjunto de condiciones suministrado, límites y orden ca n también ser suministrado. Este método construye una sola instrucción SQL UPDATE y envía directamente a la base de datos. No hace instanciar los modelos implicados y no desencadena las devoluciones de llamada de Active Record .

3

Como se trata de una importación de una sola vez, se puede hacer lo siguiente:

  1. Crear modelo usando legacy_created_at y legacy_updated_at campos.
  2. Cargar datos heredados. Haga un mapa en los campos modelo como desee. Puede usar #save y generalmente no se preocupe por usar update_all o similar, y puede usar devoluciones de llamada si lo desea.
  3. Cree una migración para cambiar el nombre de las columnas a created_at y updated_at.
47

método update_column usar en su lugar:

http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update_column

update_column(name, value) 
# Updates a single attribute of an object, without calling save. 

se salta de validación.

Las devoluciones de llamada se omiten.

columna updated_at/updated_on no se actualiza si esa columna está disponible.

Levanta un ActiveRecordError cuando se invoca a objetos nuevos, o cuando el atributo de nombre está marcado como de solo lectura.

+0

Tenga en cuenta que para las columnas serializadas tendrá que escribir el valor usted mismo de antemano. – Jared

2

¿Cuándo no está en una importación masiva, puede anular el should_record_timestamps? método en su modelo para agregar nuevas comprobaciones sobre cuándo actualizar la columna updated_at.

2

me gusta utilizar un módulo mixin para desactivar temporalmente de sellado de tiempo en un bloque:

module WithoutTimestamps 
    def without_timestamps 
    old = ActiveRecord::Base.record_timestamps 
    ActiveRecord::Base.record_timestamps = false 
    begin 
     yield 
    ensure 
     ActiveRecord::Base.record_timestamps = old 
    end 
    end 
end 

A continuación, puede utilizarlo siempre que lo necesite

class MyModel < ActiveRecord::Base 
    include WithoutTimestamps 

    def save_without_timestamps 
    without_timestamps do 
     save! 
    end 
    end 
end 

o sólo un uno así:

m = MyModel.find(1) 
WithoutTimestamps.without_timestamps do 
    m.save! 
end 
+1

Solo una advertencia, esto no es inseguro. ¡Recientemente fue mordido por esto! – Slicedpan

2

En referencia a otras respuestas, me sorprendió que las marcas de tiempo de deshabilitación para una sola modelo, como en:

User.record_timestamps = false 

funcionó para mi base de datos de desarrollo, pero no en mi base de datos de preproducción, que se ejecuta en un servidor diferente. Sin embargo funciona si inhabilito marcas de tiempo para todos los modelos con

ActiveRecord::Base.record_timestamps = false 

(Situación: modificando el atributo created_at en una migración)

21

rieles 5 proporciona una manera conveniente de actualizar un registro sin actualizar su marca de tiempo updated_at.

Usted solo necesita pasar touch:false al actualizar su registro.

>> user = User.first 
>> user.updated_at 
=> Thu, 28 Apr 2016 20:01:57 IST +05:30 
>> user.name = "Jose" 
>> user.save(touch: false) 
=> true 

>> user.updated_at 
=> Thu, 28 Apr 2016 20:01:57 IST +05:30 
+0

Esta es, de lejos, la forma más limpia de mover los registros. –

7

En Rails 3+, para un solo objeto, establezca record_timestamps para el objeto en lugar de clase. Es decir,

>> user = User.first 
>> user.updated_at 
=> Tue, 12 Apr 2016 22:47:51 GMT +00:00 
>> user.name = "Jose" 
=> "Jose" 
>> user.record_timestamps = false 
>> user.save 
=> true 
>> user.updated_at 
=> Tue, 12 Apr 2016 22:47:51 GMT +00:00 
>> User.record_timestamps 
=> true 

De esta manera, no se toca el estado global para el modelo, y usted no tiene que recordar para restaurar la configuración previa en un bloque ensure.

Cuestiones relacionadas