validator validations validates rails example callbacks after_create after ruby-on-rails callback

ruby-on-rails - validations - validates activerecord



Establecer manualmente updated_at en Rails (6)

Estoy migrando mis publicaciones de blog antiguas a mi nuevo blog de Rails, y quiero que su atributo updated_at coincida con el valor correspondiente en mi blog anterior (no la fecha en que se migraron a mi nuevo blog de Rails).

¿Cómo puedo hacer esto? Cuando configuro updated_at manualmente, se invalida con la before_save llamada before_save .

Nota: esta pregunta solo es válida para Rails <3.2.11. Las versiones más nuevas de Rails le permiten configurar manualmente las marcas de tiempo sin que se sobrescriban.


A partir de las versiones recientes de Rails (3.2.11 según el comentario de iGELs), puede establecer la propiedad updated_at en el código y el cambio se respetará al guardar.

Supongo que los rieles mantienen un registro de las propiedades "sucias" que se han cambiado manualmente y no se sobrescriben al guardar.

> note = Note.last Note Load (1.4ms) SELECT "notes".* FROM "notes" ORDER BY "notes"."id" DESC LIMIT 1 => #<Note id: 39, content: "A wee note", created_at: "2015-06-09 11:06:01", updated_at: "2015-06-09 11:06:01"> > note.updated_at = 2.years.ago => Sun, 07 Jul 2013 21:20:47 UTC +00:00 > note.save (0.4ms) BEGIN (0.8ms) UPDATE "notes" SET "updated_at" = ''2013-07-07 21:20:47.972990'' WHERE "notes"."id" = 39 (0.8ms) COMMIT => true > note => #<Note id: 39, content: "A wee note", created_at: "2015-06-09 11:06:01", updated_at: "2013-07-07 21:20:47">

Entonces, respuesta corta, las soluciones temporales ya no son necesarias en las versiones recientes de rieles.


Esto es una copia de la respuesta de Andy Gaskell:

class ActiveRecord::Base class_inheritable_writer :record_timestamps def do_without_changing_timestamps self.class.record_timestamps = false yield ensure self.class.record_timestamps = true end end


La solución es configurar temporalmente ActiveRecord :: Base.record_timestamps en falso:

ActiveRecord::Base.record_timestamps = false # Make whatever changes you want to the timestamps here ActiveRecord::Base.record_timestamps = true

Si desea una solución algo más robusta, puede intentar algo como lo que sugirió mrm:

module ActiveRecord class Base def self.without_timestamping timestamping = self.record_timestamps begin self.record_timestamps = false yield ensure self.record_timestamps = timestamping end end end end

Luego, puede realizar cambios fácilmente en los modelos sin que sus marcas de tiempo se actualicen automáticamente:

ActiveRecord::Base.without_timestamping do foo = Foo.first bar = Bar.first foo.updated_at = 1.month.ago bar.updated_at = foo.updated_at + 1.week foo.save! bar.save! end

O, si solo desea actualizar los registros de una clase específica sin marca de tiempo:

module ActiveRecord class Base # Don''t delete Rail''s ActiveRecord::Base#inherited method self.singleton_class.send(:alias_method, :__inherited__, :inherited) def self.inherited(subclass) __inherited__ # Adding class methods to `subclass` class << subclass def without_timestamping # Temporarily override record_timestamps for this class class << self def record_timestamps; false; end end yield ensure class << self remove_method :record_timestamps end end end end end end

P.ej:

Foo.without_timestamping do foo = Foo.first bar = Bar.new(foo: foo) foo.updated_at = 1.month.ago foo.save! # Timestamps not automatically updated bar.save! # Timestamps updated normally end

O puede utilizar un enfoque similar al que sugirió Venkat D., que funciona por instancia:

module ActiveRecord class Base def without_timestamping class << self def record_timestamps; false; end end yield ensure class << self remove_method :record_timestamps end end end end

P.ej:

foo = Foo.first foo.without_timestamping do foo2 = Foo.new(parent: foo) foo.updated_at = 1.month.ago foo.save! # Timestamps not automatically updated foo2.save! # Timestamps updated normally end


Si es una cosa de una sola vez, puedes activar o desactivar el record_timestamps .

ActiveRecord::Base.record_timestamps = false #set timestamps manually ActiveRecord::Base.record_timestamps = true

Cuando me topé con este problema con mi aplicación, busqué un poco y me pareció que tenía más sentido para mí. Es un inicializador al que puedo llamar donde necesito:

module ActiveRecord class Base def update_record_without_timestamping class << self def record_timestamps; false; end end save! class << self def record_timestamps; super ; end end end end end


Tomé la respuesta de Andy y la modifiqué para aceptar bloques:

module ActiveRecord class Base def without_timestamping class << self def record_timestamps; false; end end yield class << self remove_method :record_timestamps end end end end


Veo dos maneras de lograr esto fácilmente:

toque (rieles 5)

En Rails 5 puede usar el método touch y dar un time parámetro nombrado como se describe en la documentación de contacto.

foo.touch(time: old_timestamp)

update_column (Rails> = 3.1)

Si lo desea en Rails 4 e inferior o si desea evitar todas las devoluciones de llamada, puede utilizar uno de los métodos update_column o update_columns que omiten todas las devoluciones de llamada seguras o táctiles y las validaciones

foo.update_column(updated_at, old_timestamp)

o

foo.update_columns(updated_at: old_timestamp)