Есть ли способ получить старые значения записи во время after_update с помощью ActiveRecord?

StackOverflow https://stackoverflow.com/questions/607069

Вопрос

Настройка на простом примере: У меня есть 1 стол (Totals), который содержит сумму amount столбец каждой записи во второй таблице (Things).

Когда thing.amount обновляется, я бы хотел просто добавить разницу между старым и новым значением в total.sum.

Прямо сейчас я вычитаю self.amount в течение before_update и добавление self.amount в течение after_update.Это вызывает слишком большую уверенность в успехе обновления.

Ограничение: Я не хочу просто пересчитывать сумму всех транзакций.

Вопрос: Проще говоря, я хотел бы получить доступ к исходному значению во время after_update перезвонить.Какие способы вы придумали для этого?

Обновлять: Я придерживаюсь идеи Люка Франкла.Во время after_update обратный вызов, у вас все еще есть доступ к self.attr_was ценности, а это именно то, что я хотел.Я тоже решил пойти с after_update реализацию, потому что я хочу сохранить такую ​​логику в модели.Таким образом, независимо от того, как я решу обновить транзакции в будущем, я буду знать, что обновляю сумму транзакций правильно.Спасибо всем за предложения по реализации.

Это было полезно?

Решение

То же самое все говорят о транзакциях.

Тем не менее...

ActiveRecord начиная с Rails 2.1 отслеживает значения атрибутов объекта.Итак, если у вас есть атрибут total, у вас будет total_changed? метод и total_was метод, который возвращает старое значение.

Больше не нужно ничего добавлять в модель, чтобы отслеживать это.

Обновлять: Вот документация для АктивМодель::Грязный как просили.

Другие советы

Некоторые другие люди упоминают о заключении всего этого в транзакцию, но я думаю, что для вас это уже сделано; вам просто нужно запустить откат, вызвав исключение для ошибок в обратных вызовах after_*.

Видеть http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

Вся цепочка обратных вызовов сохранения, сохранения! или уничтожения выполняется внутри транзакции.Это включает в себя хуки after_*.Если все идет нормально, после завершения цепочки выполняется COMMIT.

Если обратный вызов before_* отменяет действие, выдается ROLLBACK.Вы также можете вызвать ROLLBACK, вызывающий исключение в любом из обратных вызовов, включая перехватчики after_*.Однако обратите внимание, что в этом случае клиент должен знать об этом, потому что обычное сохранение вызовет такое исключение вместо того, чтобы незаметно вернуть false.

Добавление «_was» к вашему атрибуту даст вам предыдущее значение перед сохранением данных.

Эти методы называются грязные методы методы.

Ваше здоровье!

Чтобы получить все измененные поля со старыми и новыми значениями соответственно:

person = Person.create!(:name => 'Bill')
person.name = 'Bob'
person.save
person.changes        # => {"name" => ["Bill", "Bob"]}

ActiveRecord::Грязный — это встроенный в ActiveRecord модуль для отслеживания изменений атрибутов.Таким образом, вы можете использовать thing.amount_was чтобы получить старое значение.

Добавьте это в свою модель:

def amount=(new_value)
    @old_amount = read_attribute(:amount)
    write_attribute(:amount,new_value)
end

Затем используйте @old_amount в коде after_update.

Во-первых, вы должны делать это в транзакции, чтобы гарантировать, что ваши данные будут записаны вместе.

Чтобы ответить на ваш вопрос, вы можете просто установить для переменной-члена старое значение в before_update, к которому вы затем сможете получить доступ в after_update, однако это не очень элегантное решение.

Идея 1:Оберните обновление в транзакцию базы данных, чтобы в случае сбоя обновления ваша таблица итогов не изменилась: Документы по транзакциям ActiveRecord

Идея 2:Сохраните старое значение в @old_total во время before_update.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top