Подтвердить что ты не робот

Есть ли способ избежать автоматического обновления полей метки времени Rails?

Если у вас есть столбцы DB created_at и updated_at, Rails автоматически установит эти значения при создании и обновлении объекта модели. Есть ли способ сохранить модель, не касаясь этих столбцов?

Я привожу некоторые устаревшие данные, и я хотел бы установить эти значения из соответствующих значений в (по-разному) устаревших данных. Я нахожу, когда устанавливаю их на модели, а затем сохраняю модель, Rails, похоже, переопределяет входящие значения.

Конечно, я мог бы просто назвать столбцы модели Rails по-разному, чтобы предотвратить это, но после импорта данных я хочу, чтобы Rails выполнял свою автоматическую метку времени.

4b9b3361

Ответ 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 в процессе миграции)

Ответ 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