Есть ли способ избежать автоматического обновления полей метки времени Rails?
Если у вас есть столбцы DB created_at
и updated_at
, Rails автоматически установит эти значения при создании и обновлении объекта модели. Есть ли способ сохранить модель, не касаясь этих столбцов?
Я привожу некоторые устаревшие данные, и я хотел бы установить эти значения из соответствующих значений в (по-разному) устаревших данных. Я нахожу, когда устанавливаю их на модели, а затем сохраняю модель, Rails, похоже, переопределяет входящие значения.
Конечно, я мог бы просто назвать столбцы модели Rails по-разному, чтобы предотвратить это, но после импорта данных я хочу, чтобы Rails выполнял свою автоматическую метку времени.
Ответы
Ответ 1
Сделайте это при миграции или в задаче грабли (или в новые семена базы данных, если вы находитесь на крайних рельсах):
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
Вы можете безопасно установить created_at
и updated_at
вручную, Rails не будет жаловаться.
Примечание: Это также работает на отдельных моделях, например. User.record_timestamps = false
Ответ 2
используйте вместо этого метод update_column:
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.
Валидация пропущена.
Обратные вызовы пропускаются.
Столбец updated_at/updated_on не обновляется, если этот столбец доступен.
Повышает ActiveRecordError при вызове новых объектов или когда атрибут name помечен как readonly.
Ответ 3
Rails 5 предоставляет удобный способ обновления записи без обновления ее отметки времени updated_at
: https://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-save
Вам просто нужно пройти touch:false
при обновлении вашей записи.
>> 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
Ответ 4
Вы можете установить следующее внутри своей миграции:
ActiveRecord::Base.record_timestamps = false
Или altenatively использовать update_all:
update_all (обновления, условия = nil, options = {})
Обновляет все записи с данными если они соответствуют набору условий поставляемые, лимиты и порядок также могут быть в комплект поставки. Этот метод создает один оператор SQL UPDATE и отправляет это прямо в базу данных. Оно делает не создавать экземпляры задействованных моделей и он не активирует активную запись Обратные вызовы.
Ответ 5
В Rails 3+ для одного объекта установите record_timestamps
для объекта, а не для класса. То есть.
>> 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
Таким образом, вы не трогаете глобальное состояние модели, и вам не нужно помнить о восстановлении предыдущей настройки в блоке ensure
.
Ответ 6
Так как это одноразовый импорт, вы можете сделать следующее:
- Создайте модель с помощью полей
legacy_created_at
и legacy_updated_at
.
- Загрузить устаревшие данные. По желанию вставьте в поля модели. Вы можете использовать
#save
и вообще не беспокоиться об использовании update_all
или тому подобное, и при необходимости вы можете использовать обратные вызовы.
- Создайте перенос, чтобы переименовать столбцы в
created_at
и updated_at
.
Ответ 7
Мне нравится использовать модуль mixin для временного отключения штамповки в блоке:
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
Затем вы можете использовать его там, где вам это нужно
class MyModel < ActiveRecord::Base
include WithoutTimestamps
def save_without_timestamps
without_timestamps do
save!
end
end
end
Или просто одноразовый:
m = MyModel.find(1)
WithoutTimestamps.without_timestamps do
m.save!
end
Ответ 8
Если не в массовом ввозе, вы можете переопределить значение should_record_timestamps? метод на вашей модели, чтобы добавить новые проверки, когда обновлять столбец updated_at.
Ответ 9
Ссылаясь на другие ответы, я с удивлением обнаружил, что отключение временных меток для одной модели, например, в:
User.record_timestamps = false
работал для моей базы данных разработки, но не в моей предварительной базе данных, которая работает на другом сервере. Однако он работает, если я отключу отметки времени для всех моделей с помощью
ActiveRecord::Base.record_timestamps = false
(Ситуация: изменение атрибута created_at в процессе миграции)
Ответ 10
Или, для обеспечения безопасности потоков, см. http://www.hungryfools.com/2007/07/turning-off-activerecord-timestamp.html
Ответ 11
Я не смог заставить флаг ActiveRecord::Base.record_timestamps
что-либо изменить, и единственный работающий способ - использовать ActiveRecord::Base.no_touching {}
:
ActiveRecord::Base.no_touching do
Project.first.touch # does nothing
Message.first.touch # does nothing
end
Project.no_touching do
Project.first.touch # does nothing
Message.first.touch # works, but does not touch the associated project
end
Взято из здесь.
Это очень полезно для задач rake, где вам нужно переопределить некоторые свойства глубоко связанных моделей и не беспокоиться о внутренних обратных вызовах, в то время как ваши пользователи используют атрибуты created_at
или updated_at
или те, которые используются в качестве столбцов сортировки ,
Ответ 12
Я опаздываю на вечеринку, но мы пропускаем обновление updated_at
в моем магазине:
# config/initializers/no_timestamping.rb
module ActiveRecord
class Base
def update_record_without_timestamping
class << self
def record_timestamps; false; end
end
save!
class << self
remove_method :record_timestamps
end
end
end
end
Использование:
post.something = 'whatever'
post.update_record_without_timestamping