Skip to content

Instantly share code, notes, and snippets.

@bowsersenior
Forked from millisami/gist:721466
Created November 30, 2010 16:56
Show Gist options
  • Save bowsersenior/721971 to your computer and use it in GitHub Desktop.
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
@bowsersenior
Copy link
Author

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.

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