Fixing dirty tracking on collection_of association type

This commit is contained in:
Sam Lown 2011-05-20 02:15:18 +02:00
parent fba1e53e20
commit 938bf2cf2c
3 changed files with 79 additions and 55 deletions

View file

@ -9,6 +9,7 @@
* Initialization blocks when creating new models (Peter Williams) * Initialization blocks when creating new models (Peter Williams)
* Removed railties dependency (DAddYE) * Removed railties dependency (DAddYE)
* DesignDoc cache refreshed if a database is deleted. * DesignDoc cache refreshed if a database is deleted.
* Fixing dirty tracking on collection_of association.
## 1.1.0.beta5 - 2011-04-30 ## 1.1.0.beta5 - 2011-04-30

View file

@ -153,7 +153,7 @@ module CouchRest
def #{attrib}(reload = false) def #{attrib}(reload = false)
return @#{attrib} unless @#{attrib}.nil? or reload return @#{attrib} unless @#{attrib}.nil? or reload
ary = self.#{options[:foreign_key]}.collect{|i| #{options[:proxy]}.get(i)} ary = self.#{options[:foreign_key]}.collect{|i| #{options[:proxy]}.get(i)}
@#{attrib} = ::CouchRest::CollectionOfProxy.new(ary, self, '#{options[:foreign_key]}') @#{attrib} = ::CouchRest::Model::CollectionOfProxy.new(ary, find_property('#{options[:foreign_key]}'), self)
end end
EOS EOS
end end
@ -161,7 +161,7 @@ module CouchRest
def create_collection_of_setter(attrib, options) def create_collection_of_setter(attrib, options)
class_eval <<-EOS, __FILE__, __LINE__ + 1 class_eval <<-EOS, __FILE__, __LINE__ + 1
def #{attrib}=(value) def #{attrib}=(value)
@#{attrib} = ::CouchRest::CollectionOfProxy.new(value, self, '#{options[:foreign_key]}') @#{attrib} = ::CouchRest::Model::CollectionOfProxy.new(value, find_property('#{options[:foreign_key]}'), self)
end end
EOS EOS
end end
@ -169,67 +169,63 @@ module CouchRest
end end
end end
end
# Special proxy for a collection of items so that adding and removing # Special proxy for a collection of items so that adding and removing
# to the list automatically updates the associated property. # to the list automatically updates the associated property.
class CollectionOfProxy < Array class CollectionOfProxy < CastedArray
attr_accessor :property
attr_accessor :casted_by
def initialize(array, casted_by, property) def initialize(array, property, parent)
self.property = property (array ||= []).compact!
self.casted_by = casted_by super(array, property, parent)
(array ||= []).compact! casted_by[casted_by_property.to_s] = [] # replace the original array!
casted_by[property.to_s] = [] # replace the original array! array.compact.each do |obj|
array.compact.each do |obj| check_obj(obj)
check_obj(obj) casted_by[casted_by_property.to_s] << obj.id
casted_by[property.to_s] << obj.id end
end end
super(array)
end
def << obj def << obj
check_obj(obj) check_obj(obj)
casted_by[property.to_s] << obj.id casted_by[casted_by_property.to_s] << obj.id
super(obj) super(obj)
end end
def push(obj) def push(obj)
check_obj(obj) check_obj(obj)
casted_by[property.to_s].push obj.id casted_by[casted_by_property.to_s].push obj.id
super(obj) super(obj)
end end
def unshift(obj) def unshift(obj)
check_obj(obj) check_obj(obj)
casted_by[property.to_s].unshift obj.id casted_by[casted_by_property.to_s].unshift obj.id
super(obj) super(obj)
end end
def []= index, obj def []= index, obj
check_obj(obj) check_obj(obj)
casted_by[property.to_s][index] = obj.id casted_by[casted_by_property.to_s][index] = obj.id
super(index, obj) super(index, obj)
end end
def pop def pop
casted_by[property.to_s].pop casted_by[casted_by_property.to_s].pop
super super
end end
def shift def shift
casted_by[property.to_s].shift casted_by[casted_by_property.to_s].shift
super super
end end
protected protected
def check_obj(obj)
raise "Object cannot be added to #{casted_by.class.to_s}##{casted_by_property.to_s} collection unless saved" if obj.new?
end
def check_obj(obj)
raise "Object cannot be added to #{casted_by.class.to_s}##{property.to_s} collection unless saved" if obj.new?
end end
end end
end end

View file

@ -101,7 +101,7 @@ describe "Assocations" do
it "should create an associated property and collection proxy" do it "should create an associated property and collection proxy" do
@invoice.respond_to?('entry_ids').should be_true @invoice.respond_to?('entry_ids').should be_true
@invoice.respond_to?('entry_ids=').should be_true @invoice.respond_to?('entry_ids=').should be_true
@invoice.entries.class.should eql(::CouchRest::CollectionOfProxy) @invoice.entries.class.should eql(::CouchRest::Model::CollectionOfProxy)
end end
it "should allow replacement of objects" do it "should allow replacement of objects" do
@ -154,6 +154,33 @@ describe "Assocations" do
@invoice.entries.should be_empty @invoice.entries.should be_empty
end end
# Account for dirty tracking
describe "dirty tracking" do
it "should register changes on push" do
@invoice.changed?.should be_false
@invoice.entries << @entries[0]
@invoice.changed?.should be_true
end
it "should register changes on pop" do
@invoice.entries << @entries[0]
@invoice.save
@invoice.changed?.should be_false
@invoice.entries.pop
@invoice.changed?.should be_true
end
it "should register id changes on push" do
@invoice.entry_ids << @entries[0].id
@invoice.changed?.should be_true
end
it "should register id changes on pop" do
@invoice.entry_ids << @entries[0].id
@invoice.save
@invoice.changed?.should be_false
@invoice.entry_ids.pop
@invoice.changed?.should be_true
end
end
describe "proxy" do describe "proxy" do
it "should ensure new entries to proxy are matched" do it "should ensure new entries to proxy are matched" do