Created
May 23, 2011 16:02
-
-
Save slaskis/986945 to your computer and use it in GitHub Desktop.
An example of how DataMapper fails to destroy a model that has a many-to-many relation to the same class (as demonstrated in the docs)
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
require "rubygems" | |
require "datamapper" | |
DataMapper::Logger.new(STDOUT,:debug) | |
DataMapper.setup(:default, "sqlite3::memory:") | |
#DataMapper.setup(:default, "postgres://localhost/dm-test") | |
class Entry | |
include DataMapper::Resource | |
default_scope.update( :order => [ :name.asc ] ) | |
property :id, Serial | |
property :name, String, :required => true | |
has 1, :related, :model => Entry, :constraint => :destroy | |
belongs_to :related, Entry, :required => false | |
belongs_to :collection | |
before :destroy do | |
puts "Destroying Entry (#{name})" | |
end | |
end | |
class Collection | |
include DataMapper::Resource | |
default_scope.update( :order => [ :name.asc ] ) | |
property :id, Serial | |
property :name, String, :required => true | |
has n, :entries, :constraint => :destroy | |
belongs_to :person | |
before :destroy do | |
puts "Destroying Collection (#{name})" | |
end | |
end | |
class Person | |
include DataMapper::Resource | |
default_scope.update( :order => [ :name.asc ] ) | |
property :id, Serial | |
property :name, String, :length => 0...1024, :default => "" | |
has n, :collections, :constraint => :destroy | |
has n, :connections, :child_key => [:source_id] | |
has n, :related, self, :through => :connections, :via => :target | |
before :destroy do | |
puts "Destroying Person (#{name})" | |
end | |
end | |
############################################ | |
# Connection between two people, usually the | |
# relation between an Agent and an Artist. | |
############################################ | |
class Connection | |
include DataMapper::Resource | |
belongs_to :source, 'Person', :key => true | |
belongs_to :target, 'Person', :key => true | |
end | |
DataMapper.finalize | |
DataMapper.auto_migrate! | |
p1 = Person.create(:name => "A") | |
p1.collections.create(:name => "A1", :entries => [{:name => "A1E1"},{:name => "A1E2"},{:name => "A1E3"},{:name => "A1E4"}]) | |
p1.collections.create(:name => "A2", :entries => [{:name => "A2E1"},{:name => "A2E2"},{:name => "A2E3"},{:name => "A2E4"}]) | |
p1.collections.create(:name => "A3", :entries => [{:name => "A3E1"},{:name => "A3E2"},{:name => "A3E3"},{:name => "A3E4"}]) | |
p1.collections.create(:name => "A4", :entries => [{:name => "A4E1"},{:name => "A4E2"},{:name => "A4E3"},{:name => "A4E4"}]) | |
p2 = Person.create(:name => "B") | |
p2.collections.create(:name => "B1", :entries => [{:name => "B1E1"},{:name => "B1E2"},{:name => "B1E3"},{:name => "B1E4"}]) | |
p2.collections.create(:name => "B2", :entries => [{:name => "B2E1"},{:name => "B2E2"},{:name => "B2E3"},{:name => "B2E4"}]) | |
p2.collections.create(:name => "B3", :entries => [{:name => "B3E1"},{:name => "B3E2"},{:name => "B3E3"},{:name => "B3E4"}]) | |
p2.collections.create(:name => "B4", :entries => [{:name => "B4E1"},{:name => "B4E2"},{:name => "B4E3"},{:name => "B4E4"}]) | |
# Connecting the two will make #destroy fail | |
p2.related << p1 | |
p2.save | |
# 1. Clearing it first will make it destroyable... | |
#p2.related.clear | |
#p2.save # Saving is important! | |
# 2. Or reloading it (when it hasn't been persisted) | |
#p2.reload | |
# All Entry and Collection that's related to p2 is being destroyed, but not p2 itself (and the destroy hook is never fired) | |
p "Was destroyed?", p2.destroy # => true if either 1 or 2 is commented out, otherwise false | |
puts DataMapper::VERSION # => 1.1.0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I found that if Person.related and Person.connections gets a
:constaints => :skip
it works, and then if I set related.clear; save in the before destroy hook it's the way I want it to be.In other word I believe that's where the destroy chain silently fails in many-to-many associations...