Created

Embed URL

HTTPS clone URL

SSH clone URL

You can clone with HTTPS or SSH.

Download Gist
View gist:1612
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
module HasAttributesFor
module ActiveRecord
def self.included(ar)
ar.extend ClassMethods
end
 
module ClassMethods
def has_attributes_for(association)
primary_key_name = reflect_on_association(association).primary_key_name
class_eval %{
def #{association}_attributes=(params)
@original_#{association} ||= #{association}.clone
existing = new_record? ? {} : #{association}.index_by(&:id)
keep = []
(params||[]).each do |attributes|
id = attributes[:id].to_i
if id && r = existing[id]
r.attributes = attributes.except(:id)
else
# we use build so that it doesn't save the record yet instead of <<
r = #{association}.build(attributes.except(:id))
end
keep << r
end
# remove all the original records that were no longer referenced
# this will not actually delete these records, only unreference them
deletions = self.#{association} - keep
deletions.each do |r|
# important to use target here to remove the record from memory but not the database
self.#{association}.target.delete(r)
end
end
}
class_eval %{
def original_#{association}
@original_#{association}
end
def original_#{association}=(value)
@original_#{association} = value
end
}, __FILE__, __LINE__
class_eval %{
before_update do |p|
if p.original_#{association}
new_records = p.#{association}
p.original_#{association}.each do |r|
p.#{association}.delete(r) unless new_records.member?(r)
end
end
p.#{association}.each do |r|
if r.changed?
r.#{primary_key_name} = p.id
r.save
end
end
end
after_save do |p|
p.original_#{association} = nil
end
}, __FILE__, __LINE__
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.