collectiveidea / audited

Audited (formerly acts_as_audited) is an ORM extension that logs all changes to your Rails models.
MIT License
3.34k stars 645 forks source link

`#touch` on record results in `NoMethodError` #698

Closed brodyhoskins closed 4 months ago

brodyhoskins commented 4 months ago

When a record hasn't changed Audited raises NoMethodError.

Audited: 5.4.3 Ruby: 3.2.3 Ruby on Rails: 7.1.3

Specifically I'm running code like:

blob = ActiveStorage::Blob.create_and_upload!(
         io: file,
         filename: ,
         content_type: 'application/pdf',
       )
record.label.attach(blob) # exception raised here

I can reproduce ths issue with:

irb(main):001> Record.last.touch
  Record Load (4.1ms)  SELECT "records".* FROM "records" ORDER BY "records"."id" DESC LIMIT $1  [["LIMIT", 1]]
  TRANSACTION (0.1ms)  BEGIN
  Record Update (12.9ms)  UPDATE "records" SET "updated_at" = $1 WHERE "records"."id" = $2  [["updated_at", "2024-02-16 02:36:45.130987"], ["id", 18769]]
  TRANSACTION (0.4ms)  ROLLBACK
[GEM_ROOT]/gems/audited-5.4.3/lib/audited/auditor.rb:243:in `audited_changes': undefined method `except' for nil:NilClass (NoMethodError)

        all_changes = all_changes.except(*self.class.readonly_attributes.to_a) if exclude_readonly_attrs
                                 ^^^^^^^
irb(main):002> Record.last.previous_changes
  Record Load (5.1ms)  SELECT "records".* FROM "records" ORDER BY "records"."id" DESC LIMIT $1  [["LIMIT", 1]]
=> nil

The backtrace shows:

NoMethodError: undefined method `except' for nil:NilClass all_changes = all_changes.except(*self.class.readonly_attributes.to_a) if exclude_readonly_attrs ^^^^^^^
        end

        all_changes = all_changes.except(*self.class.readonly_attributes.to_a) if exclude_readonly_attrs

        filtered_changes = \

---
auditor.rb:243: audited_changes(...)
[GEM_ROOT]/gems/audited-5.4.3/lib/audited/auditor.rb:243:in `audited_changes'
  auditor.rb  345  audit_touch(...)
[GEM_ROOT]/gems/audited-5.4.3/lib/audited/auditor.rb:345:in `audit_touch'
  callbacks.rb  403  block in make_lambda(...)
[GEM_ROOT]/gems/activesupport-7.1.3/lib/active_support/callbacks.rb:403:in `block in make_lambda'

My theory is that because record itself didn't change, all_changes is nil rather than a Hash.

brodyhoskins commented 4 months ago

Sorry folks, I found some custom code in our project that was erroneously overriding #previous_changes on the model.