-
-
Save bowsersenior/721971 to your computer and use it in GitHub Desktop.
| %w(rubygems mongoid rspec).each do |gem| | |
| require gem | |
| end | |
| Mongoid.configure do |config| | |
| name = "dirty_track_test" | |
| host = "localhost" | |
| config.master = Mongo::Connection.new.db(name) | |
| config.persist_in_safe_mode = false | |
| end | |
| RSpec.configure do |config| | |
| config.before(:each) do | |
| Mongoid.master.collections.reject { |c| c.name == 'system.indexes'}.each(&:drop) | |
| end | |
| end | |
| class Person | |
| include Mongoid::Document | |
| field :name | |
| embeds_one :address | |
| embeds_many :phones | |
| references_many :projects | |
| # dirty tracking of embedded documents | |
| attr_writer :embedded_changes, :referenced_changes | |
| def referenced_changes | |
| puts "SELF: #{(self.methods - Object.methods).sort.to_yaml}" | |
| puts "CHILDREN: #{((self.associations)).inspect}" | |
| @referenced_changes ||= begin | |
| self.associations.keys.each do |assoc_name| | |
| self.send(assoc_name).inject({}) do |memo, obj| | |
| memo.merge(obj.each{|c| c.send(:changes) if c.send(:changed?)}) | |
| end | |
| end | |
| end | |
| end | |
| def embedded_changes | |
| @embedded_changes ||= begin | |
| self._children.inject({}) do |memo, child| | |
| memo.merge(child.changes) if child.changed? | |
| end | |
| end | |
| end | |
| def changes | |
| original_value = super | |
| if original_value.blank? | |
| embedded_changes # need to merge these two hashes | |
| referenced_changes # but make sure to detect nil values | |
| else | |
| original_value.merge(embedded_changes).merge(referenced_changes) | |
| end | |
| end | |
| def changed? | |
| super || self._children.any?(&:changed?) # what about changes to referenced docs? | |
| end | |
| end | |
| class Address | |
| include Mongoid::Document | |
| field :city | |
| embedded_in :person, :inverse_of => :address | |
| end | |
| class Phone | |
| include Mongoid::Document | |
| field :number, :type => Integer | |
| embedded_in :person, :inverse_of => :phones | |
| end | |
| class Project | |
| include Mongoid::Document | |
| field :title | |
| referenced_in :person, :inverse_of => :projects | |
| end | |
| describe Person do | |
| context "parent document" do | |
| it "should detect the changes" do | |
| @person = Person.new(:name => "Sachin") | |
| @person.save! | |
| @person.name = "Sagar" | |
| @person.changed.should be_true | |
| end | |
| end | |
| context "parent document with embedded one document" do | |
| it "should detect the changes of the embedded one address document when the address city is changed" do | |
| @person = Person.new(:name => "Sachin") | |
| @person.create_address(:city => "Kathmandu") | |
| @person.changed?.should be_false | |
| @person.address.city = "Lalitpur" | |
| @person.changed?.should be_true | |
| @person.changes["city"].should include("Lalitpur") | |
| end | |
| end | |
| context "parent document with embedded many document" do | |
| it "should detect the changes of the embedded many phones document when the phone number is changed" do | |
| @person = Person.new(:name => "Sachin") | |
| @person.phones.create!(:number => 980) | |
| @person.phones.first.number.should == 980 | |
| @person.changed?.should be_false | |
| @person.phones.first.number = 400 | |
| @person.changed?.should be_true | |
| @person.changes["number"].should include(400) | |
| end | |
| end | |
| context "parent document with references many documents" do | |
| it "should detect the changes of the referenced many project document when the project title is changed" do | |
| @person = Person.create!(:title => "Sachin") | |
| @project = Project.new(:name => "Gliding") | |
| @person.projects << @project | |
| @person.changes | |
| @person.changed?.should be_true | |
| # @person.changes["title"].should include("Gliding") | |
| end | |
| end | |
| end |
I looked further into this and I don't think it will work. The problem is that references work very differently than embedded docs and there are a lot of difficulties in tracking their changes. Sorry, but I can only recommend that you go with the embedded_changes only or find another way of solving the problem. FYI, there is a dirty_associations plugin for ActiveRecord: https://github.com/daphonz/dirty_associations
@bowsersenior, that dirty_associations plugin is for ActiveRecord and it blows out when I install it.
Yes, I know dirty_associations is for activerecord. If you look at the code for dirty_associations, you can get some ideas on how to do something similar for mongoid. But I think you'll see that it won't be easy! Also, dirty_associations doesn't record changes to an associated record, only the addition or removal of an associated record.
This is the diff patch you made.
diff --git a/dirty-track.rb b/dirty-track.rb
index f461b97..598c3b7 100644
--- a/dirty-track.rb
+++ b/dirty-track.rb
@@ -30,8 +30,10 @@ class Person
puts "CHILDREN: #{((self.associations)).inspect}"
But still it doesn't work. Yup, I know that you don't have time. But can you plz look at it and just run
ruby dirty-track.rbto make the spec green!!