Last active
January 31, 2024 09:16
-
-
Save fadhlirahim/683cff8c99018a1d886e to your computer and use it in GitHub Desktop.
Awesome simple solution for Rails ActiveRecord dirty tracking associations
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Credit Brandon Weiss of http://anti-pattern.com/dirty-associations-with-activerecord | |
# app/models/dirty_associations.rb | |
module DirtyAssociations | |
attr_accessor :dirty | |
attr_accessor :_record_changes | |
def make_dirty(record) | |
self.dirty = true | |
self._record_changes = record | |
end | |
def changed? | |
dirty || super | |
end | |
end | |
# app/models/lolrus.rb | |
class Lolrus | |
include DirtyAssociations | |
has_many :buckets, | |
:after_add => :make_dirty, | |
:after_remove => :make_dirty | |
end | |
# Usage | |
lol = Lolrus.create! | |
lol.buckets << Bucket.new | |
lol.changed? | |
# => true | |
lol._record_changes | |
# => #<Bucket# ... > | |
lol._record_changes.changed? | |
# => true | |
lol._record_changes.changes? | |
# for example ... | |
# => {[attr] => [old_value, new_value]} |
Neat!
When adding or removing multiple records only the last one would be present in _record_changes
.
You could rewrite made_dirty
to get all changed records like so:
def make_dirty(record)
self.dirty = true
self._record_changes ||= []
self._record_changes << record
end
Also, reload
doesn't reset the _record_changes
. You can overload the reload
method like so:
def reload(*)
super.tap do
self._record_changes = nil
end
end
@yourivdlans hi. thanks for you solution. He does not mentioned any reload methods. Can you elaborate why we need reload?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Just passing by.. 👋 😄