简体   繁体   中英

Reporting on changes before the end of an ActiveRecord transaction commits. (Ruby on Rails)

I am doing a complex series of database interactions within nested transactions using ActiveRecord (Rails), involving various model.update(...) , model.where(...).first_or_create(..) etc

Right before the transaction ends I'd like to report on what's actually changed and about to be written. Presumably ActiveRecord holds this information but I've not been able to work out where.

My code would be something like ( semi-pseudocode )

def run options
  begin
  ActiveRecord::Base.transaction do |tranny|
    options[:files].each do |file|
      raw_data = open(file)
      complex_data_stuff raw_data, options
    end
    report
  rescue => e
    "it all went horribly wrong, here's why: #{e.message}"
  end
end

def report tranny
  changes = {}
  tranny.whatschanged?.each do |ch|
    changes[ch.model.class.name] = {} unless changes[ch.model.class.name]
    if changes[ch.model.class.name][ch.kind_of_update]
      changes[ch.model.class.name][ch.kind_of_update] += 1
    else
      changes[ch.model.class.name][ch.kind_of_update] = 1
    end
  end
  changes
end

How would I achieve something like this?

http://api.rubyonrails.org/classes/ActiveModel/Dirty.html

This is the latest version of "dirty models", which keeps track of the differences between the current object and the saved version. You access the changes via a "changes" method like in your attempt.

I added some extra stuff in one of my projects to store what was changed in the last update: this is stored in an instance variable, so is only accessable in the specific object in memory (ie you can't see it if you reload it from the database).

module ActiveRecord
  class Base
    attr_accessor :changed_in_last_save
    before_save :set_changed_in_last_save_hash

    def set_changed_in_last_save_hash
      self.changed_in_last_save_hash = self.changes
    end

    def changed_in_last_save
      self.changed_in_last_save_hash || {}
    end
  end
end

You definitely need ActiveModel::Dirty, you probably don't need my thing, just mentioned it as it's similar :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM