Skip to content

Instantly share code, notes, and snippets.

@ideasasylum
Created May 10, 2016 14:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ideasasylum/e0be5ef7c3603f22e26aa0c4dd590385 to your computer and use it in GitHub Desktop.
Save ideasasylum/e0be5ef7c3603f22e26aa0c4dd590385 to your computer and use it in GitHub Desktop.
Dirty state tracking for previous changes
module PreviouslyDirty
extend ActiveSupport::Concern
include ActiveModel::AttributeMethods
included do
attribute_method_suffix '_previously_changed?', '_previously_was'
end
# Handle <tt>*_previously_changed?</tt> for +method_missing+.
def attribute_previously_changed?(attr, options = {}) #:nodoc:
result = previous_changes.include?(attr)
result &&= options[:to] == previous_changes[attr][1] if options.key?(:to)
result &&= options[:from] == previous_changes[attr][0] if options.key?(:from)
result
end
# Handle <tt>*_was</tt> for +method_missing+.
def attribute_previously_was(attr) # :nodoc:
attribute_previously_changed?(attr) ? previous_changes[attr][0] : __send__(attr)
end
end
@ideasasylum
Copy link
Author

ideasasylum commented May 10, 2016

Rails has some great dirty state tracking methods but this information is cleared after the commit. This prevents you doing things like:

user = 'new_email@example.com'
user.save!
send_some_email if user.email_changed? # this'll never execute

but all the changes from the last commit are stored in the previous_changes hash so this gist adds the attribute_previously_changed? and attribute_previously_was methods following the same pattern as the regular change methods

user.email = 'new_email@example.com'
user.save!
send_some_email if user.email_previously_changed?  #=> now executes
old_email = user.email_previously_was                         #=> the old email address

I find this very handy for conditional after_commit callbacks or, even better, for avoiding callbacks altogether and putting that logic in the controller (on the basis that callbacks can be a complete PITA)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment