Created
November 30, 2010 10:16
-
-
Save millisami/721466 to your computer and use it in GitHub Desktop.
Mongoid Dirty Tracking
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%w(rubygems mongoid rspec).each do |gem| | |
require gem | |
end | |
require 'hijacker' | |
Hijacker.configure do | |
uri 'druby://localhost:8787' | |
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.inject({}) do |memo, child| | |
memo.merge(child.each{|c| c.send(:changes) if c.send(:changed?)}) | |
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 | |
referenced_changes | |
else | |
original_value.merge(embedded_changes).merge(referenced_changes) | |
end | |
end | |
def changed? | |
super || self._children.any?(&:changed?) | |
end | |
end | |
Hijacker.spy(Person, | |
:only => :instance_methods, | |
:uri => 'druby://localhost:8787') | |
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment