Skip to content

Instantly share code, notes, and snippets.

@brianjlandau
Created April 29, 2010 16:55
Show Gist options
  • Select an option

  • Save brianjlandau/383876 to your computer and use it in GitHub Desktop.

Select an option

Save brianjlandau/383876 to your computer and use it in GitHub Desktop.
module ActiveRecord
module ChangeableAttribute
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def changeable_attribute_writer(*attrbs)
attrbs.each do |attrb|
if attrb.to_s =~ /_attributes$/
change_name = attrb.to_s.gsub(/_attributes$/, '').to_sym
define_method "#{attrb}_with_changeable=" do |new_value|
result = self.send("#{attrb}_without_changeable=", new_value)
# The attribute already has an unsaved change.
if changed_attributes.include?(change_name)
changed_attributes.delete(change_name) unless self.send(change_name.to_sym).changed?
else
if self.send(change_name.to_sym).changed?
old = send(change_name.to_sym).changes.inject({}) do |h, changes|
h[changes.first] = changes.last.first
end
changed_attributes[change_name] = old
end
end
result
end
elsif attrb.to_s =~ /_ids$/
define_method "#{attrb}_with_changeable=" do |new_value|
if changed_attributes.include?(attrb)
old = changed_attributes[attrb]
else
old = send(attrb.to_sym)
end
result = self.send("#{attrb}_without_changeable=", new_value)
if changed_attributes.include?(attrb)
changed_attributes.delete(attrb) unless field_changed?(attrb, old.try(:sort), new_value.try(:sort))
else
changed_attributes[attrb] = old if field_changed?(attrb, old.try(:sort), new_value.try(:sort))
end
result
end
else
define_method "#{attrb}_with_changeable=" do |new_value|
# The attribute already has an unsaved change.
if changed_attributes.include?(flag)
old = changed_attributes[flag]
changed_attributes.delete(flag) unless field_changed?(flag, old, new_value)
else
old = send(flag.to_sym)
changed_attributes[flag] = old if field_changed?(flag, old, new_value)
end
self.send("#{attrb}_without_changeable=", new_value)
end
end
alias_method_chain "#{attrb}=".to_sym, :changeable
end
end
end
private
def attribute_change(attr)
if attribute_changed?(attr)
if self.class.reflections.map(&:first).include?(attr)
__send__(attr).changes
else
[changed_attributes[attr], __send__(attr)]
end
end
end
end
end
ActiveRecord::Base.send :include, ActiveRecord::ChangeableAttribute
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment