audited 4.7.0 → 4.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of audited might be problematic. Click here for more details.
- checksums.yaml +5 -5
 - data/.gitignore +0 -1
 - data/.rubocop.yml +25 -0
 - data/.travis.yml +32 -27
 - data/Appraisals +29 -12
 - data/CHANGELOG.md +77 -1
 - data/README.md +73 -17
 - data/gemfiles/rails42.gemfile +3 -0
 - data/gemfiles/rails50.gemfile +3 -0
 - data/gemfiles/rails51.gemfile +3 -0
 - data/gemfiles/rails52.gemfile +4 -2
 - data/gemfiles/rails60.gemfile +10 -0
 - data/gemfiles/rails61.gemfile +10 -0
 - data/lib/audited/audit.rb +31 -25
 - data/lib/audited/auditor.rb +102 -29
 - data/lib/audited/version.rb +1 -1
 - data/lib/audited.rb +2 -1
 - data/lib/generators/audited/templates/add_version_to_auditable_index.rb +21 -0
 - data/lib/generators/audited/templates/install.rb +1 -1
 - data/lib/generators/audited/upgrade_generator.rb +4 -0
 - data/spec/audited/audit_spec.rb +88 -21
 - data/spec/audited/auditor_spec.rb +240 -54
 - data/spec/audited/sweeper_spec.rb +15 -6
 - data/spec/audited_spec_helpers.rb +3 -1
 - data/spec/rails_app/app/assets/config/manifest.js +1 -0
 - data/spec/rails_app/app/controllers/application_controller.rb +2 -0
 - data/spec/rails_app/config/application.rb +5 -0
 - data/spec/rails_app/config/database.yml +1 -0
 - data/spec/spec_helper.rb +3 -1
 - data/spec/support/active_record/models.rb +22 -0
 - data/spec/support/active_record/schema.rb +4 -2
 - data/test/db/version_6.rb +2 -0
 - data/test/test_helper.rb +1 -2
 - data/test/upgrade_generator_test.rb +10 -0
 - metadata +59 -22
 - data/gemfiles/rails40.gemfile +0 -9
 - data/gemfiles/rails41.gemfile +0 -8
 
    
        data/lib/audited/auditor.rb
    CHANGED
    
    | 
         @@ -34,6 +34,16 @@ module Audited 
     | 
|
| 
       34 
34 
     | 
    
         
             
                  # * +require_comment+ - Ensures that audit_comment is supplied before
         
     | 
| 
       35 
35 
     | 
    
         
             
                  #   any create, update or destroy operation.
         
     | 
| 
       36 
36 
     | 
    
         
             
                  # * +max_audits+ - Limits the number of stored audits.
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                  # * +redacted+ - Changes to these fields will be logged, but the values
         
     | 
| 
      
 39 
     | 
    
         
            +
                  #   will not. This is useful, for example, if you wish to audit when a
         
     | 
| 
      
 40 
     | 
    
         
            +
                  #   password is changed, without saving the actual password in the log.
         
     | 
| 
      
 41 
     | 
    
         
            +
                  #   To store values as something other than '[REDACTED]', pass an argument
         
     | 
| 
      
 42 
     | 
    
         
            +
                  #   to the redaction_value option.
         
     | 
| 
      
 43 
     | 
    
         
            +
                  #
         
     | 
| 
      
 44 
     | 
    
         
            +
                  #     class User < ActiveRecord::Base
         
     | 
| 
      
 45 
     | 
    
         
            +
                  #       audited redacted: :password, redaction_value: SecureRandom.uuid
         
     | 
| 
      
 46 
     | 
    
         
            +
                  #     end
         
     | 
| 
       37 
47 
     | 
    
         
             
                  #
         
     | 
| 
       38 
48 
     | 
    
         
             
                  # * +if+ - Only audit the model when the given function returns true
         
     | 
| 
       39 
49 
     | 
    
         
             
                  # * +unless+ - Only audit the model when the given function returns false
         
     | 
| 
         @@ -55,7 +65,7 @@ module Audited 
     | 
|
| 
       55 
65 
     | 
    
         | 
| 
       56 
66 
     | 
    
         
             
                    class_attribute :audit_associated_with, instance_writer: false
         
     | 
| 
       57 
67 
     | 
    
         
             
                    class_attribute :audited_options,       instance_writer: false
         
     | 
| 
       58 
     | 
    
         
            -
                    attr_accessor : 
     | 
| 
      
 68 
     | 
    
         
            +
                    attr_accessor :audit_version, :audit_comment
         
     | 
| 
       59 
69 
     | 
    
         | 
| 
       60 
70 
     | 
    
         
             
                    self.audited_options = options
         
     | 
| 
       61 
71 
     | 
    
         
             
                    normalize_audited_options
         
     | 
| 
         @@ -90,6 +100,8 @@ module Audited 
     | 
|
| 
       90 
100 
     | 
    
         
             
                end
         
     | 
| 
       91 
101 
     | 
    
         | 
| 
       92 
102 
     | 
    
         
             
                module AuditedInstanceMethods
         
     | 
| 
      
 103 
     | 
    
         
            +
                  REDACTED = '[REDACTED]'
         
     | 
| 
      
 104 
     | 
    
         
            +
                  
         
     | 
| 
       93 
105 
     | 
    
         
             
                  # Temporarily turns off auditing while saving.
         
     | 
| 
       94 
106 
     | 
    
         
             
                  def save_without_auditing
         
     | 
| 
       95 
107 
     | 
    
         
             
                    without_auditing { save }
         
     | 
| 
         @@ -105,6 +117,21 @@ module Audited 
     | 
|
| 
       105 
117 
     | 
    
         
             
                    self.class.without_auditing(&block)
         
     | 
| 
       106 
118 
     | 
    
         
             
                  end
         
     | 
| 
       107 
119 
     | 
    
         | 
| 
      
 120 
     | 
    
         
            +
                  # Temporarily turns on auditing while saving.
         
     | 
| 
      
 121 
     | 
    
         
            +
                  def save_with_auditing
         
     | 
| 
      
 122 
     | 
    
         
            +
                    with_auditing { save }
         
     | 
| 
      
 123 
     | 
    
         
            +
                  end
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                  # Executes the block with the auditing callbacks enabled.
         
     | 
| 
      
 126 
     | 
    
         
            +
                  #
         
     | 
| 
      
 127 
     | 
    
         
            +
                  #   @foo.with_auditing do
         
     | 
| 
      
 128 
     | 
    
         
            +
                  #     @foo.save
         
     | 
| 
      
 129 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 130 
     | 
    
         
            +
                  #
         
     | 
| 
      
 131 
     | 
    
         
            +
                  def with_auditing(&block)
         
     | 
| 
      
 132 
     | 
    
         
            +
                    self.class.with_auditing(&block)
         
     | 
| 
      
 133 
     | 
    
         
            +
                  end
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
       108 
135 
     | 
    
         
             
                  # Gets an array of the revisions available
         
     | 
| 
       109 
136 
     | 
    
         
             
                  #
         
     | 
| 
       110 
137 
     | 
    
         
             
                  #   user.revisions.each do |revision|
         
     | 
| 
         @@ -142,7 +169,16 @@ module Audited 
     | 
|
| 
       142 
169 
     | 
    
         | 
| 
       143 
170 
     | 
    
         
             
                  # List of attributes that are audited.
         
     | 
| 
       144 
171 
     | 
    
         
             
                  def audited_attributes
         
     | 
| 
       145 
     | 
    
         
            -
                    attributes.except(*non_audited_columns)
         
     | 
| 
      
 172 
     | 
    
         
            +
                    audited_attributes = attributes.except(*self.class.non_audited_columns)
         
     | 
| 
      
 173 
     | 
    
         
            +
                    normalize_enum_changes(audited_attributes)
         
     | 
| 
      
 174 
     | 
    
         
            +
                  end
         
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
      
 176 
     | 
    
         
            +
                  # Returns a list combined of record audits and associated audits.
         
     | 
| 
      
 177 
     | 
    
         
            +
                  def own_and_associated_audits
         
     | 
| 
      
 178 
     | 
    
         
            +
                    Audited.audit_class.unscoped
         
     | 
| 
      
 179 
     | 
    
         
            +
                    .where('(auditable_type = :type AND auditable_id = :id) OR (associated_type = :type AND associated_id = :id)',
         
     | 
| 
      
 180 
     | 
    
         
            +
                      type: self.class.name, id: id)
         
     | 
| 
      
 181 
     | 
    
         
            +
                    .order(created_at: :desc)
         
     | 
| 
       146 
182 
     | 
    
         
             
                  end
         
     | 
| 
       147 
183 
     | 
    
         | 
| 
       148 
184 
     | 
    
         
             
                  # Combine multiple audits into one.
         
     | 
| 
         @@ -159,18 +195,9 @@ module Audited 
     | 
|
| 
       159 
195 
     | 
    
         | 
| 
       160 
196 
     | 
    
         
             
                  protected
         
     | 
| 
       161 
197 
     | 
    
         | 
| 
       162 
     | 
    
         
            -
                  def non_audited_columns
         
     | 
| 
       163 
     | 
    
         
            -
                    self.class.non_audited_columns
         
     | 
| 
       164 
     | 
    
         
            -
                  end
         
     | 
| 
       165 
     | 
    
         
            -
             
     | 
| 
       166 
     | 
    
         
            -
                  def audited_columns
         
     | 
| 
       167 
     | 
    
         
            -
                    self.class.audited_columns
         
     | 
| 
       168 
     | 
    
         
            -
                  end
         
     | 
| 
       169 
     | 
    
         
            -
             
     | 
| 
       170 
198 
     | 
    
         
             
                  def revision_with(attributes)
         
     | 
| 
       171 
199 
     | 
    
         
             
                    dup.tap do |revision|
         
     | 
| 
       172 
200 
     | 
    
         
             
                      revision.id = id
         
     | 
| 
       173 
     | 
    
         
            -
                      revision.send :instance_variable_set, '@attributes', self.attributes if rails_below?('4.2.0')
         
     | 
| 
       174 
201 
     | 
    
         
             
                      revision.send :instance_variable_set, '@new_record', destroyed?
         
     | 
| 
       175 
202 
     | 
    
         
             
                      revision.send :instance_variable_set, '@persisted', !destroyed?
         
     | 
| 
       176 
203 
     | 
    
         
             
                      revision.send :instance_variable_set, '@readonly', false
         
     | 
| 
         @@ -193,25 +220,62 @@ module Audited 
     | 
|
| 
       193 
220 
     | 
    
         
             
                    end
         
     | 
| 
       194 
221 
     | 
    
         
             
                  end
         
     | 
| 
       195 
222 
     | 
    
         | 
| 
       196 
     | 
    
         
            -
                  def rails_below?(rails_version)
         
     | 
| 
       197 
     | 
    
         
            -
                    Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new(rails_version)
         
     | 
| 
       198 
     | 
    
         
            -
                  end
         
     | 
| 
       199 
     | 
    
         
            -
             
     | 
| 
       200 
223 
     | 
    
         
             
                  private
         
     | 
| 
       201 
224 
     | 
    
         | 
| 
       202 
225 
     | 
    
         
             
                  def audited_changes
         
     | 
| 
       203 
226 
     | 
    
         
             
                    all_changes = respond_to?(:changes_to_save) ? changes_to_save : changes
         
     | 
| 
       204 
     | 
    
         
            -
                     
     | 
| 
       205 
     | 
    
         
            -
                       
     | 
| 
       206 
     | 
    
         
            -
             
     | 
| 
       207 
     | 
    
         
            -
                       
     | 
| 
      
 227 
     | 
    
         
            +
                    filtered_changes = \
         
     | 
| 
      
 228 
     | 
    
         
            +
                      if audited_options[:only].present?
         
     | 
| 
      
 229 
     | 
    
         
            +
                        all_changes.slice(*self.class.audited_columns)
         
     | 
| 
      
 230 
     | 
    
         
            +
                      else
         
     | 
| 
      
 231 
     | 
    
         
            +
                        all_changes.except(*self.class.non_audited_columns)
         
     | 
| 
      
 232 
     | 
    
         
            +
                      end
         
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
      
 234 
     | 
    
         
            +
                    filtered_changes = redact_values(filtered_changes)
         
     | 
| 
      
 235 
     | 
    
         
            +
                    filtered_changes = normalize_enum_changes(filtered_changes)
         
     | 
| 
      
 236 
     | 
    
         
            +
                    filtered_changes.to_hash
         
     | 
| 
      
 237 
     | 
    
         
            +
                  end
         
     | 
| 
      
 238 
     | 
    
         
            +
             
     | 
| 
      
 239 
     | 
    
         
            +
                  def normalize_enum_changes(changes)
         
     | 
| 
      
 240 
     | 
    
         
            +
                    self.class.defined_enums.each do |name, values|
         
     | 
| 
      
 241 
     | 
    
         
            +
                      if changes.has_key?(name)
         
     | 
| 
      
 242 
     | 
    
         
            +
                        changes[name] = \
         
     | 
| 
      
 243 
     | 
    
         
            +
                          if changes[name].is_a?(Array)
         
     | 
| 
      
 244 
     | 
    
         
            +
                            changes[name].map { |v| values[v] }
         
     | 
| 
      
 245 
     | 
    
         
            +
                          elsif rails_below?('5.0')
         
     | 
| 
      
 246 
     | 
    
         
            +
                            changes[name]
         
     | 
| 
      
 247 
     | 
    
         
            +
                          else
         
     | 
| 
      
 248 
     | 
    
         
            +
                            values[changes[name]]
         
     | 
| 
      
 249 
     | 
    
         
            +
                          end
         
     | 
| 
      
 250 
     | 
    
         
            +
                      end
         
     | 
| 
       208 
251 
     | 
    
         
             
                    end
         
     | 
| 
      
 252 
     | 
    
         
            +
                    changes
         
     | 
| 
      
 253 
     | 
    
         
            +
                  end
         
     | 
| 
      
 254 
     | 
    
         
            +
             
     | 
| 
      
 255 
     | 
    
         
            +
                  def redact_values(filtered_changes)
         
     | 
| 
      
 256 
     | 
    
         
            +
                    [audited_options[:redacted]].flatten.compact.each do |option|
         
     | 
| 
      
 257 
     | 
    
         
            +
                      changes = filtered_changes[option.to_s]
         
     | 
| 
      
 258 
     | 
    
         
            +
                      new_value = audited_options[:redaction_value] || REDACTED
         
     | 
| 
      
 259 
     | 
    
         
            +
                      if changes.is_a? Array
         
     | 
| 
      
 260 
     | 
    
         
            +
                        values = changes.map { new_value }
         
     | 
| 
      
 261 
     | 
    
         
            +
                      else
         
     | 
| 
      
 262 
     | 
    
         
            +
                        values = new_value
         
     | 
| 
      
 263 
     | 
    
         
            +
                      end
         
     | 
| 
      
 264 
     | 
    
         
            +
                      hash = Hash[option.to_s, values]
         
     | 
| 
      
 265 
     | 
    
         
            +
                      filtered_changes.merge!(hash)
         
     | 
| 
      
 266 
     | 
    
         
            +
                    end
         
     | 
| 
      
 267 
     | 
    
         
            +
             
     | 
| 
      
 268 
     | 
    
         
            +
                    filtered_changes
         
     | 
| 
      
 269 
     | 
    
         
            +
                  end
         
     | 
| 
      
 270 
     | 
    
         
            +
             
     | 
| 
      
 271 
     | 
    
         
            +
                  def rails_below?(rails_version)
         
     | 
| 
      
 272 
     | 
    
         
            +
                    Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new(rails_version)
         
     | 
| 
       209 
273 
     | 
    
         
             
                  end
         
     | 
| 
       210 
274 
     | 
    
         | 
| 
       211 
275 
     | 
    
         
             
                  def audits_to(version = nil)
         
     | 
| 
       212 
276 
     | 
    
         
             
                    if version == :previous
         
     | 
| 
       213 
     | 
    
         
            -
                      version = if self. 
     | 
| 
       214 
     | 
    
         
            -
                                  self. 
     | 
| 
      
 277 
     | 
    
         
            +
                      version = if self.audit_version
         
     | 
| 
      
 278 
     | 
    
         
            +
                                  self.audit_version - 1
         
     | 
| 
       215 
279 
     | 
    
         
             
                                else
         
     | 
| 
       216 
280 
     | 
    
         
             
                                  previous = audits.descending.offset(1).first
         
     | 
| 
       217 
281 
     | 
    
         
             
                                  previous ? previous.version : 1
         
     | 
| 
         @@ -226,7 +290,7 @@ module Audited 
     | 
|
| 
       226 
290 
     | 
    
         
             
                  end
         
     | 
| 
       227 
291 
     | 
    
         | 
| 
       228 
292 
     | 
    
         
             
                  def audit_update
         
     | 
| 
       229 
     | 
    
         
            -
                    unless (changes = audited_changes).empty? && audit_comment.blank?
         
     | 
| 
      
 293 
     | 
    
         
            +
                    unless (changes = audited_changes).empty? && (audit_comment.blank? || audited_options[:update_with_comment_only] == false)
         
     | 
| 
       230 
294 
     | 
    
         
             
                      write_audit(action: 'update', audited_changes: changes,
         
     | 
| 
       231 
295 
     | 
    
         
             
                                  comment: audit_comment)
         
     | 
| 
       232 
296 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -290,17 +354,12 @@ module Audited 
     | 
|
| 
       290 
354 
     | 
    
         | 
| 
       291 
355 
     | 
    
         
             
                  def run_conditional_check(condition, matching: true)
         
     | 
| 
       292 
356 
     | 
    
         
             
                    return true if condition.blank?
         
     | 
| 
       293 
     | 
    
         
            -
             
     | 
| 
       294 
357 
     | 
    
         
             
                    return condition.call(self) == matching if condition.respond_to?(:call)
         
     | 
| 
       295 
     | 
    
         
            -
                    return send(condition) == matching if respond_to?(condition.to_sym)
         
     | 
| 
      
 358 
     | 
    
         
            +
                    return send(condition) == matching if respond_to?(condition.to_sym, true)
         
     | 
| 
       296 
359 
     | 
    
         | 
| 
       297 
360 
     | 
    
         
             
                    true
         
     | 
| 
       298 
361 
     | 
    
         
             
                  end
         
     | 
| 
       299 
362 
     | 
    
         | 
| 
       300 
     | 
    
         
            -
                  def auditing_enabled=(val)
         
     | 
| 
       301 
     | 
    
         
            -
                    self.class.auditing_enabled = val
         
     | 
| 
       302 
     | 
    
         
            -
                  end
         
     | 
| 
       303 
     | 
    
         
            -
             
     | 
| 
       304 
363 
     | 
    
         
             
                  def reconstruct_attributes(audits)
         
     | 
| 
       305 
364 
     | 
    
         
             
                    attributes = {}
         
     | 
| 
       306 
365 
     | 
    
         
             
                    audits.each { |audit| attributes.merge!(audit.new_attributes) }
         
     | 
| 
         @@ -338,6 +397,20 @@ module Audited 
     | 
|
| 
       338 
397 
     | 
    
         
             
                    enable_auditing if auditing_was_enabled
         
     | 
| 
       339 
398 
     | 
    
         
             
                  end
         
     | 
| 
       340 
399 
     | 
    
         | 
| 
      
 400 
     | 
    
         
            +
                  # Executes the block with auditing enabled.
         
     | 
| 
      
 401 
     | 
    
         
            +
                  #
         
     | 
| 
      
 402 
     | 
    
         
            +
                  #   Foo.with_auditing do
         
     | 
| 
      
 403 
     | 
    
         
            +
                  #     @foo.save
         
     | 
| 
      
 404 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 405 
     | 
    
         
            +
                  #
         
     | 
| 
      
 406 
     | 
    
         
            +
                  def with_auditing
         
     | 
| 
      
 407 
     | 
    
         
            +
                    auditing_was_enabled = auditing_enabled
         
     | 
| 
      
 408 
     | 
    
         
            +
                    enable_auditing
         
     | 
| 
      
 409 
     | 
    
         
            +
                    yield
         
     | 
| 
      
 410 
     | 
    
         
            +
                  ensure
         
     | 
| 
      
 411 
     | 
    
         
            +
                    disable_auditing unless auditing_was_enabled
         
     | 
| 
      
 412 
     | 
    
         
            +
                  end
         
     | 
| 
      
 413 
     | 
    
         
            +
             
     | 
| 
       341 
414 
     | 
    
         
             
                  def disable_auditing
         
     | 
| 
       342 
415 
     | 
    
         
             
                    self.auditing_enabled = false
         
     | 
| 
       343 
416 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -355,7 +428,7 @@ module Audited 
     | 
|
| 
       355 
428 
     | 
    
         
             
                  end
         
     | 
| 
       356 
429 
     | 
    
         | 
| 
       357 
430 
     | 
    
         
             
                  def auditing_enabled
         
     | 
| 
       358 
     | 
    
         
            -
                    Audited.store.fetch("#{table_name}_auditing_enabled", true)
         
     | 
| 
      
 431 
     | 
    
         
            +
                    Audited.store.fetch("#{table_name}_auditing_enabled", true) && Audited.auditing_enabled
         
     | 
| 
       359 
432 
     | 
    
         
             
                  end
         
     | 
| 
       360 
433 
     | 
    
         | 
| 
       361 
434 
     | 
    
         
             
                  def auditing_enabled=(val)
         
     | 
    
        data/lib/audited/version.rb
    CHANGED
    
    
    
        data/lib/audited.rb
    CHANGED
    
    | 
         @@ -2,7 +2,7 @@ require 'active_record' 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module Audited
         
     | 
| 
       4 
4 
     | 
    
         
             
              class << self
         
     | 
| 
       5 
     | 
    
         
            -
                attr_accessor :ignored_attributes, :current_user_method, :max_audits
         
     | 
| 
      
 5 
     | 
    
         
            +
                attr_accessor :ignored_attributes, :current_user_method, :max_audits, :auditing_enabled
         
     | 
| 
       6 
6 
     | 
    
         
             
                attr_writer :audit_class
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
                def audit_class
         
     | 
| 
         @@ -21,6 +21,7 @@ module Audited 
     | 
|
| 
       21 
21 
     | 
    
         
             
              @ignored_attributes = %w(lock_version created_at updated_at created_on updated_on)
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
              @current_user_method = :current_user
         
     | 
| 
      
 24 
     | 
    
         
            +
              @auditing_enabled = true
         
     | 
| 
       24 
25 
     | 
    
         
             
            end
         
     | 
| 
       25 
26 
     | 
    
         | 
| 
       26 
27 
     | 
    
         
             
            require 'audited/auditor'
         
     | 
| 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class <%= migration_class_name %> < <%= migration_parent %>
         
     | 
| 
      
 2 
     | 
    
         
            +
              def self.up
         
     | 
| 
      
 3 
     | 
    
         
            +
                if index_exists?(:audits, [:auditable_type, :auditable_id], name: index_name)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  remove_index :audits, name: index_name
         
     | 
| 
      
 5 
     | 
    
         
            +
                  add_index :audits, [:auditable_type, :auditable_id, :version], name: index_name
         
     | 
| 
      
 6 
     | 
    
         
            +
                end
         
     | 
| 
      
 7 
     | 
    
         
            +
              end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              def self.down
         
     | 
| 
      
 10 
     | 
    
         
            +
                if index_exists?(:audits, [:auditable_type, :auditable_id, :version], name: index_name)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  remove_index :audits, name: index_name
         
     | 
| 
      
 12 
     | 
    
         
            +
                  add_index :audits, [:auditable_type, :auditable_id], name: index_name
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              private
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              def index_name
         
     | 
| 
      
 19 
     | 
    
         
            +
                'auditable_index'
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -17,7 +17,7 @@ class <%= migration_class_name %> < <%= migration_parent %> 
     | 
|
| 
       17 
17 
     | 
    
         
             
                  t.column :created_at, :datetime
         
     | 
| 
       18 
18 
     | 
    
         
             
                end
         
     | 
| 
       19 
19 
     | 
    
         | 
| 
       20 
     | 
    
         
            -
                add_index :audits, [:auditable_type, :auditable_id], :name => 'auditable_index'
         
     | 
| 
      
 20 
     | 
    
         
            +
                add_index :audits, [:auditable_type, :auditable_id, :version], :name => 'auditable_index'
         
     | 
| 
       21 
21 
     | 
    
         
             
                add_index :audits, [:associated_type, :associated_id], :name => 'associated_index'
         
     | 
| 
       22 
22 
     | 
    
         
             
                add_index :audits, [:user_id, :user_type], :name => 'user_index'
         
     | 
| 
       23 
23 
     | 
    
         
             
                add_index :audits, :request_uuid
         
     | 
| 
         @@ -58,6 +58,10 @@ module Audited 
     | 
|
| 
       58 
58 
     | 
    
         
             
                    if indexes.any? { |i| i.columns == %w[associated_id associated_type] }
         
     | 
| 
       59 
59 
     | 
    
         
             
                      yield :revert_polymorphic_indexes_order
         
     | 
| 
       60 
60 
     | 
    
         
             
                    end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                    if indexes.any? { |i| i.columns == %w[auditable_type auditable_id] }
         
     | 
| 
      
 63 
     | 
    
         
            +
                      yield :add_version_to_auditable_index
         
     | 
| 
      
 64 
     | 
    
         
            +
                    end
         
     | 
| 
       61 
65 
     | 
    
         
             
                  end
         
     | 
| 
       62 
66 
     | 
    
         
             
                end
         
     | 
| 
       63 
67 
     | 
    
         
             
              end
         
     | 
    
        data/spec/audited/audit_spec.rb
    CHANGED
    
    | 
         @@ -1,5 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require "spec_helper"
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            SingleCov.covered! uncovered: 1 # Rails version check
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
       3 
5 
     | 
    
         
             
            describe Audited::Audit do
         
     | 
| 
       4 
6 
     | 
    
         
             
              let(:user) { Models::ActiveRecord::User.new name: "Testing" }
         
     | 
| 
       5 
7 
     | 
    
         | 
| 
         @@ -38,43 +40,64 @@ describe Audited::Audit do 
     | 
|
| 
       38 
40 
     | 
    
         
             
                  end
         
     | 
| 
       39 
41 
     | 
    
         
             
                end
         
     | 
| 
       40 
42 
     | 
    
         | 
| 
       41 
     | 
    
         
            -
                 
     | 
| 
       42 
     | 
    
         
            -
                   
     | 
| 
      
 43 
     | 
    
         
            +
                context "when a custom audit class is not configured" do
         
     | 
| 
      
 44 
     | 
    
         
            +
                  it "should default to #{described_class}" do
         
     | 
| 
      
 45 
     | 
    
         
            +
                    TempModel.audited
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                    record = TempModel.create
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                    audit = record.audits.first
         
     | 
| 
      
 50 
     | 
    
         
            +
                    expect(audit).to be_a Audited::Audit
         
     | 
| 
      
 51 
     | 
    
         
            +
                    expect(audit.respond_to?(:custom_method)).to be false
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
              end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
              describe "#audited_changes" do
         
     | 
| 
      
 57 
     | 
    
         
            +
                let(:audit) { Audited.audit_class.new }
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                it "can unserialize yaml from text columns" do
         
     | 
| 
      
 60 
     | 
    
         
            +
                  audit.audited_changes = {foo: "bar"}
         
     | 
| 
      
 61 
     | 
    
         
            +
                  expect(audit.audited_changes).to eq foo: "bar"
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                it "does not unserialize from binary columns" do
         
     | 
| 
      
 65 
     | 
    
         
            +
                  allow(Audited::YAMLIfTextColumnType).to receive(:text_column?).and_return(false)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  audit.audited_changes = {foo: "bar"}
         
     | 
| 
      
 67 
     | 
    
         
            +
                  expect(audit.audited_changes).to eq "{:foo=>\"bar\"}"
         
     | 
| 
      
 68 
     | 
    
         
            +
                end
         
     | 
| 
      
 69 
     | 
    
         
            +
              end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
              describe "#undo" do
         
     | 
| 
      
 72 
     | 
    
         
            +
                let(:user) { Models::ActiveRecord::User.create(name: "John") }
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                it "undos changes" do
         
     | 
| 
       43 
75 
     | 
    
         
             
                  user.update_attribute(:name, 'Joe')
         
     | 
| 
       44 
76 
     | 
    
         
             
                  user.audits.last.undo
         
     | 
| 
       45 
77 
     | 
    
         
             
                  user.reload
         
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
78 
     | 
    
         
             
                  expect(user.name).to eq("John")
         
     | 
| 
       48 
79 
     | 
    
         
             
                end
         
     | 
| 
       49 
80 
     | 
    
         | 
| 
       50 
     | 
    
         
            -
                it " 
     | 
| 
       51 
     | 
    
         
            -
                  user = Models::ActiveRecord::User.create(name: "John")
         
     | 
| 
      
 81 
     | 
    
         
            +
                it "undos destroy" do
         
     | 
| 
       52 
82 
     | 
    
         
             
                  user.destroy
         
     | 
| 
       53 
83 
     | 
    
         
             
                  user.audits.last.undo
         
     | 
| 
       54 
84 
     | 
    
         
             
                  user = Models::ActiveRecord::User.find_by(name: "John")
         
     | 
| 
       55 
85 
     | 
    
         
             
                  expect(user.name).to eq("John")
         
     | 
| 
       56 
86 
     | 
    
         
             
                end
         
     | 
| 
       57 
87 
     | 
    
         | 
| 
       58 
     | 
    
         
            -
                it " 
     | 
| 
       59 
     | 
    
         
            -
                  user  
     | 
| 
      
 88 
     | 
    
         
            +
                it "undos creation" do
         
     | 
| 
      
 89 
     | 
    
         
            +
                  user # trigger create
         
     | 
| 
       60 
90 
     | 
    
         
             
                  expect {user.audits.last.undo}.to change(Models::ActiveRecord::User, :count).by(-1)
         
     | 
| 
       61 
91 
     | 
    
         
             
                end
         
     | 
| 
       62 
92 
     | 
    
         | 
| 
       63 
     | 
    
         
            -
                 
     | 
| 
       64 
     | 
    
         
            -
                   
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
                    record = TempModel.create
         
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
                    audit = record.audits.first
         
     | 
| 
       70 
     | 
    
         
            -
                    expect(audit).to be_a Audited::Audit
         
     | 
| 
       71 
     | 
    
         
            -
                    expect(audit.respond_to?(:custom_method)).to be false
         
     | 
| 
       72 
     | 
    
         
            -
                  end
         
     | 
| 
      
 93 
     | 
    
         
            +
                it "fails when trying to undo unknown" do
         
     | 
| 
      
 94 
     | 
    
         
            +
                  audit = user.audits.last
         
     | 
| 
      
 95 
     | 
    
         
            +
                  audit.action = 'oops'
         
     | 
| 
      
 96 
     | 
    
         
            +
                  expect { audit.undo }.to raise_error("invalid action given oops")
         
     | 
| 
       73 
97 
     | 
    
         
             
                end
         
     | 
| 
       74 
98 
     | 
    
         
             
              end
         
     | 
| 
       75 
99 
     | 
    
         | 
| 
       76 
100 
     | 
    
         
             
              describe "user=" do
         
     | 
| 
       77 
     | 
    
         
            -
             
     | 
| 
       78 
101 
     | 
    
         
             
                it "should be able to set the user to a model object" do
         
     | 
| 
       79 
102 
     | 
    
         
             
                  subject.user = user
         
     | 
| 
       80 
103 
     | 
    
         
             
                  expect(subject.user).to eq(user)
         
     | 
| 
         @@ -110,11 +133,9 @@ describe Audited::Audit do 
     | 
|
| 
       110 
133 
     | 
    
         
             
                  subject.user = user
         
     | 
| 
       111 
134 
     | 
    
         
             
                  expect(subject.username).to be_nil
         
     | 
| 
       112 
135 
     | 
    
         
             
                end
         
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
136 
     | 
    
         
             
              end
         
     | 
| 
       115 
137 
     | 
    
         | 
| 
       116 
138 
     | 
    
         
             
              describe "revision" do
         
     | 
| 
       117 
     | 
    
         
            -
             
     | 
| 
       118 
139 
     | 
    
         
             
                it "should recreate attributes" do
         
     | 
| 
       119 
140 
     | 
    
         
             
                  user = Models::ActiveRecord::User.create name: "1"
         
     | 
| 
       120 
141 
     | 
    
         
             
                  5.times {|i| user.update_attribute :name, (i + 2).to_s }
         
     | 
| 
         @@ -148,6 +169,34 @@ describe Audited::Audit do 
     | 
|
| 
       148 
169 
     | 
    
         
             
                end
         
     | 
| 
       149 
170 
     | 
    
         
             
              end
         
     | 
| 
       150 
171 
     | 
    
         | 
| 
      
 172 
     | 
    
         
            +
              describe ".collection_cache_key" do
         
     | 
| 
      
 173 
     | 
    
         
            +
                if ActiveRecord::VERSION::MAJOR >= 5
         
     | 
| 
      
 174 
     | 
    
         
            +
                  it "uses created at" do
         
     | 
| 
      
 175 
     | 
    
         
            +
                    Audited::Audit.delete_all
         
     | 
| 
      
 176 
     | 
    
         
            +
                    audit = Models::ActiveRecord::User.create(name: "John").audits.last
         
     | 
| 
      
 177 
     | 
    
         
            +
                    audit.update_columns(created_at: Time.zone.parse('2018-01-01'))
         
     | 
| 
      
 178 
     | 
    
         
            +
                    expect(Audited::Audit.collection_cache_key).to match(/-20180101\d+$/)
         
     | 
| 
      
 179 
     | 
    
         
            +
                  end
         
     | 
| 
      
 180 
     | 
    
         
            +
                else
         
     | 
| 
      
 181 
     | 
    
         
            +
                  it "is not defined" do
         
     | 
| 
      
 182 
     | 
    
         
            +
                    expect { Audited::Audit.collection_cache_key }.to raise_error(NoMethodError)
         
     | 
| 
      
 183 
     | 
    
         
            +
                  end
         
     | 
| 
      
 184 
     | 
    
         
            +
                end
         
     | 
| 
      
 185 
     | 
    
         
            +
              end
         
     | 
| 
      
 186 
     | 
    
         
            +
             
     | 
| 
      
 187 
     | 
    
         
            +
              describe ".assign_revision_attributes" do
         
     | 
| 
      
 188 
     | 
    
         
            +
                it "dups when frozen" do
         
     | 
| 
      
 189 
     | 
    
         
            +
                  user.freeze
         
     | 
| 
      
 190 
     | 
    
         
            +
                  assigned = Audited::Audit.assign_revision_attributes(user, name: "Bar")
         
     | 
| 
      
 191 
     | 
    
         
            +
                  expect(assigned.name).to eq "Bar"
         
     | 
| 
      
 192 
     | 
    
         
            +
                end
         
     | 
| 
      
 193 
     | 
    
         
            +
             
     | 
| 
      
 194 
     | 
    
         
            +
                it "ignores unassignable attributes" do
         
     | 
| 
      
 195 
     | 
    
         
            +
                  assigned = Audited::Audit.assign_revision_attributes(user, oops: "Bar")
         
     | 
| 
      
 196 
     | 
    
         
            +
                  expect(assigned.name).to eq "Testing"
         
     | 
| 
      
 197 
     | 
    
         
            +
                end
         
     | 
| 
      
 198 
     | 
    
         
            +
              end
         
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
       151 
200 
     | 
    
         
             
              it "should set the version number on create" do
         
     | 
| 
       152 
201 
     | 
    
         
             
                user = Models::ActiveRecord::User.create! name: "Set Version Number"
         
     | 
| 
       153 
202 
     | 
    
         
             
                expect(user.audits.first.version).to eq(1)
         
     | 
| 
         @@ -213,6 +262,25 @@ describe Audited::Audit do 
     | 
|
| 
       213 
262 
     | 
    
         
             
                  end
         
     | 
| 
       214 
263 
     | 
    
         
             
                end
         
     | 
| 
       215 
264 
     | 
    
         | 
| 
      
 265 
     | 
    
         
            +
                it "should support nested as_user" do
         
     | 
| 
      
 266 
     | 
    
         
            +
                  Audited::Audit.as_user("sidekiq") do
         
     | 
| 
      
 267 
     | 
    
         
            +
                    company = Models::ActiveRecord::Company.create name: "The auditors"
         
     | 
| 
      
 268 
     | 
    
         
            +
                    company.name = "The Auditors, Inc"
         
     | 
| 
      
 269 
     | 
    
         
            +
                    company.save
         
     | 
| 
      
 270 
     | 
    
         
            +
                    expect(company.audits[-1].user).to eq("sidekiq")
         
     | 
| 
      
 271 
     | 
    
         
            +
             
     | 
| 
      
 272 
     | 
    
         
            +
                    Audited::Audit.as_user(user) do
         
     | 
| 
      
 273 
     | 
    
         
            +
                      company.name = "NEW Auditors, Inc"
         
     | 
| 
      
 274 
     | 
    
         
            +
                      company.save
         
     | 
| 
      
 275 
     | 
    
         
            +
                      expect(company.audits[-1].user).to eq(user)
         
     | 
| 
      
 276 
     | 
    
         
            +
                    end
         
     | 
| 
      
 277 
     | 
    
         
            +
             
     | 
| 
      
 278 
     | 
    
         
            +
                    company.name = "LAST Auditors, Inc"
         
     | 
| 
      
 279 
     | 
    
         
            +
                    company.save
         
     | 
| 
      
 280 
     | 
    
         
            +
                    expect(company.audits[-1].user).to eq("sidekiq")
         
     | 
| 
      
 281 
     | 
    
         
            +
                  end
         
     | 
| 
      
 282 
     | 
    
         
            +
                end
         
     | 
| 
      
 283 
     | 
    
         
            +
             
     | 
| 
       216 
284 
     | 
    
         
             
                it "should record usernames" do
         
     | 
| 
       217 
285 
     | 
    
         
             
                  Audited::Audit.as_user(user.name) do
         
     | 
| 
       218 
286 
     | 
    
         
             
                    company = Models::ActiveRecord::Company.create name: "The auditors"
         
     | 
| 
         @@ -263,6 +331,5 @@ describe Audited::Audit do 
     | 
|
| 
       263 
331 
     | 
    
         
             
                  }.to raise_exception('expected')
         
     | 
| 
       264 
332 
     | 
    
         
             
                  expect(Audited.store[:audited_user]).to be_nil
         
     | 
| 
       265 
333 
     | 
    
         
             
                end
         
     | 
| 
       266 
     | 
    
         
            -
             
     | 
| 
       267 
334 
     | 
    
         
             
              end
         
     | 
| 
       268 
335 
     | 
    
         
             
            end
         
     |