module ModelsAuditor::Audit::InstanceMethods

Public Instance Methods

do_audit_init_snapshot() click to toggle source
# File lib/models_auditor/audit.rb, line 54
def do_audit_init_snapshot
  return unless ModelsAuditor.config.audit_enabled
  return unless is_audit_enabled?
  mode = get_audit_mode
  return unless AUDIT_SNAPSHOT_MODES.include?(mode)
  ma_store_initial_state(ModelsAuditor.store)
end
do_audit_process() click to toggle source
# File lib/models_auditor/audit.rb, line 62
def do_audit_process
  return unless ModelsAuditor.config.audit_enabled
  return unless is_audit_enabled?
  mode    = get_audit_mode
  options = get_audit_options
  store   = ModelsAuditor.store

  initial_data = ma_get_initial_state(store)
  current_data = ma_auditor_get_data

  action =
    case
      when transaction_include_any_action?([:create])
        ModelsAuditor::AuditRecord::ACTION_CREATE
      when transaction_include_any_action?([:update])
        ModelsAuditor::AuditRecord::ACTION_UPDATE
      when transaction_include_any_action?([:destroy])
        ModelsAuditor::AuditRecord::ACTION_DESTROY
    end

  bridge =
    if options[:bridge]
      options[:bridge].each_with_object({}) { |(key, model_name), o| o[key] = {model_name => __send__(key)} }
    end

  begin
    if (request_data = store[:audit_request_data]).present?
      body =
        case
          when AUDIT_SNAPSHOT_MODES.include?(mode)
            ma_eliminate_not_changed_keys(initial_data, current_data)
          when AUDIT_CHANGES_MODES.include?(mode)
            current_data
          else
            raise ArgumentError.new('Incorrect value of argument audit_type')
        end

      request_data[:records_attributes] << {
        object_id:    self.id,
        object_type:  self.class.name,
        content:      body,
        action:       action,
        bridge:       bridge
      }
    end
  rescue StandardError => e
    ModelsAuditor.log_error("Couldn't generate log changes of #{self.class.name} id: #{self.try(:id)}")
    ModelsAuditor.log_error(e.message)
    ModelsAuditor.log_error(e.backtrace.take(100).join("\n"))
  end
end
get_audit_mode() click to toggle source
# File lib/models_auditor/audit.rb, line 30
def get_audit_mode
  mode = self.class.instance_variable_get(:@audit_mode)
  if mode.nil?
    self.class.column_names.include?(self.class.inheritance_column) &&
      self.class.superclass.instance_variable_get(:@audit_enabled) ?
      self.class.superclass.instance_variable_get(:@audit_mode) :
      nil
  else
    mode
  end
end
get_audit_options() click to toggle source
# File lib/models_auditor/audit.rb, line 42
def get_audit_options
  settings = self.class.instance_variable_get(:@audit_settings)
  if settings.nil?
    self.class.column_names.include?(self.class.inheritance_column) &&
      self.class.superclass.instance_variable_get(:@audit_enabled) ?
      self.class.superclass.instance_variable_get(:@audit_settings) :
      {}
  else
    settings
  end
end
is_audit_enabled?() click to toggle source
# File lib/models_auditor/audit.rb, line 24
def is_audit_enabled?
  self.class.instance_variable_get(:@audit_enabled) ||
    (self.class.column_names.include?(self.class.inheritance_column) &&
      self.class.superclass.instance_variable_get(:@audit_enabled))
end

Private Instance Methods

ma_auditor_get_data() click to toggle source

Получает сериализованные данные для аудита

# File lib/models_auditor/audit.rb, line 155
def ma_auditor_get_data
  options      = get_audit_options
  audit_params = options[:params]
  mode         = get_audit_mode
  case mode
    when AUDIT_MODE_JSON
      self.as_json(audit_params)
    when AUDIT_MODE_SERIALIZER
      if (serializer = options[:serializer]).blank?
        raise ArgumentError.new('Required option :serializer for AUDIT_MODE_SERIALIZER was not passed')
      end
      serializer.new(self, audit_params || {}).as_json
    when AUDIT_MODE_METHOD
      if (method = options[:serializer]).blank?
        raise ArgumentError.new('Required option :method for AUDIT_MODE_METHOD was not passed')
      end
      unless self.respond_to?(method)
        raise ArgumentError.new("Passed method '#{method}' is undefined")
      end
      self.__send__(method)
    when AUDIT_MODE_CHANGES_ONLY
      self.previous_changes
    else
      raise ArgumentError.new("Incorrect value of argument audit_type #{mode}")
  end
end
ma_eliminate_not_changed_keys(old_hash, new_hash) click to toggle source

Сравнивает два хэша, оставляя только отличающиеся по значению ключи @return [Hash] filtered result with different attributes only

# File lib/models_auditor/audit.rb, line 118
def ma_eliminate_not_changed_keys(old_hash, new_hash)
  case
    # Равны или оба nil
    when old_hash == new_hash
      {}
    # Один из них nil
    when (old_hash && new_hash).nil?
      (old_hash || new_hash).keys.each_with_object({}) do |key, o|
        if (was = old_hash.try(:[], key)) != (now = new_hash.try(:[], key))
          o[key] = [was, now]
        end
      end
    else # Оба не nil
      (old_hash.keys | new_hash.keys).each_with_object({}) do |key, o|
        if (was = old_hash[key]) != (now = new_hash[key])
          o[key] = [was, now]
        end
      end
  end
end
ma_get_initial_state(store) click to toggle source

Получает сериализованные данные для аудита подготовленные при инициализации сущности @return [Hash|nil] Начальные данные

# File lib/models_auditor/audit.rb, line 150
def ma_get_initial_state(store)
  store[:initial_states].try(:[], self.class.name).try(:[], self.id)
end
ma_store_initial_state(store) click to toggle source

Запоминает сериализованные данные для аудита

Вызывать данный метод следует в коллбэке after_initialize
Или в любом другом месте до изменения значений аттрибутов
# File lib/models_auditor/audit.rb, line 142
def ma_store_initial_state(store)
  store[:initial_states]    ||= {}
  states_of_mclass          = (store[:initial_states][self.class.name] ||= {})
  states_of_mclass[self.id] ||= ma_auditor_get_data
end