jonbell-mongo_mapper 0.8.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +33 -0
  3. data/UPGRADES +7 -0
  4. data/bin/mmconsole +60 -0
  5. data/examples/attr_accessible.rb +22 -0
  6. data/examples/attr_protected.rb +22 -0
  7. data/examples/cache_key.rb +24 -0
  8. data/examples/custom_types.rb +24 -0
  9. data/examples/identity_map.rb +33 -0
  10. data/examples/identity_map/automatic.rb +8 -0
  11. data/examples/identity_map/middleware.rb +14 -0
  12. data/examples/keys.rb +40 -0
  13. data/examples/modifiers/set.rb +25 -0
  14. data/examples/plugins.rb +41 -0
  15. data/examples/querying.rb +35 -0
  16. data/examples/safe.rb +43 -0
  17. data/examples/scopes.rb +52 -0
  18. data/examples/validating/embedded_docs.rb +29 -0
  19. data/lib/mongo_mapper.rb +79 -0
  20. data/lib/mongo_mapper/connection.rb +83 -0
  21. data/lib/mongo_mapper/document.rb +41 -0
  22. data/lib/mongo_mapper/embedded_document.rb +31 -0
  23. data/lib/mongo_mapper/exceptions.rb +27 -0
  24. data/lib/mongo_mapper/extensions/array.rb +19 -0
  25. data/lib/mongo_mapper/extensions/binary.rb +22 -0
  26. data/lib/mongo_mapper/extensions/boolean.rb +44 -0
  27. data/lib/mongo_mapper/extensions/date.rb +25 -0
  28. data/lib/mongo_mapper/extensions/float.rb +14 -0
  29. data/lib/mongo_mapper/extensions/hash.rb +14 -0
  30. data/lib/mongo_mapper/extensions/integer.rb +19 -0
  31. data/lib/mongo_mapper/extensions/kernel.rb +9 -0
  32. data/lib/mongo_mapper/extensions/nil_class.rb +18 -0
  33. data/lib/mongo_mapper/extensions/object.rb +27 -0
  34. data/lib/mongo_mapper/extensions/object_id.rb +30 -0
  35. data/lib/mongo_mapper/extensions/set.rb +20 -0
  36. data/lib/mongo_mapper/extensions/string.rb +18 -0
  37. data/lib/mongo_mapper/extensions/time.rb +29 -0
  38. data/lib/mongo_mapper/plugins.rb +15 -0
  39. data/lib/mongo_mapper/plugins/accessible.rb +44 -0
  40. data/lib/mongo_mapper/plugins/associations.rb +97 -0
  41. data/lib/mongo_mapper/plugins/associations/base.rb +124 -0
  42. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +29 -0
  43. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +24 -0
  44. data/lib/mongo_mapper/plugins/associations/collection.rb +27 -0
  45. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +40 -0
  46. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +127 -0
  47. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  48. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +109 -0
  49. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +32 -0
  50. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +24 -0
  51. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +14 -0
  52. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +40 -0
  53. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
  54. data/lib/mongo_mapper/plugins/associations/proxy.rb +139 -0
  55. data/lib/mongo_mapper/plugins/caching.rb +21 -0
  56. data/lib/mongo_mapper/plugins/callbacks.rb +241 -0
  57. data/lib/mongo_mapper/plugins/clone.rb +22 -0
  58. data/lib/mongo_mapper/plugins/descendants.rb +17 -0
  59. data/lib/mongo_mapper/plugins/dirty.rb +124 -0
  60. data/lib/mongo_mapper/plugins/document.rb +41 -0
  61. data/lib/mongo_mapper/plugins/dynamic_querying.rb +43 -0
  62. data/lib/mongo_mapper/plugins/dynamic_querying/dynamic_finder.rb +44 -0
  63. data/lib/mongo_mapper/plugins/embedded_document.rb +48 -0
  64. data/lib/mongo_mapper/plugins/equality.rb +17 -0
  65. data/lib/mongo_mapper/plugins/identity_map.rb +128 -0
  66. data/lib/mongo_mapper/plugins/indexes.rb +12 -0
  67. data/lib/mongo_mapper/plugins/inspect.rb +15 -0
  68. data/lib/mongo_mapper/plugins/keys.rb +313 -0
  69. data/lib/mongo_mapper/plugins/keys/key.rb +59 -0
  70. data/lib/mongo_mapper/plugins/logger.rb +18 -0
  71. data/lib/mongo_mapper/plugins/modifiers.rb +112 -0
  72. data/lib/mongo_mapper/plugins/pagination.rb +14 -0
  73. data/lib/mongo_mapper/plugins/persistence.rb +69 -0
  74. data/lib/mongo_mapper/plugins/protected.rb +53 -0
  75. data/lib/mongo_mapper/plugins/querying.rb +176 -0
  76. data/lib/mongo_mapper/plugins/querying/decorator.rb +46 -0
  77. data/lib/mongo_mapper/plugins/querying/plucky_methods.rb +15 -0
  78. data/lib/mongo_mapper/plugins/rails.rb +58 -0
  79. data/lib/mongo_mapper/plugins/safe.rb +28 -0
  80. data/lib/mongo_mapper/plugins/sci.rb +32 -0
  81. data/lib/mongo_mapper/plugins/scopes.rb +21 -0
  82. data/lib/mongo_mapper/plugins/serialization.rb +76 -0
  83. data/lib/mongo_mapper/plugins/timestamps.rb +22 -0
  84. data/lib/mongo_mapper/plugins/userstamps.rb +15 -0
  85. data/lib/mongo_mapper/plugins/validations.rb +50 -0
  86. data/lib/mongo_mapper/support/descendant_appends.rb +45 -0
  87. data/lib/mongo_mapper/version.rb +4 -0
  88. data/rails/init.rb +19 -0
  89. data/test/_NOTE_ON_TESTING +1 -0
  90. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +63 -0
  91. data/test/functional/associations/test_belongs_to_proxy.rb +93 -0
  92. data/test/functional/associations/test_in_array_proxy.rb +319 -0
  93. data/test/functional/associations/test_many_documents_as_proxy.rb +229 -0
  94. data/test/functional/associations/test_many_documents_proxy.rb +615 -0
  95. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +176 -0
  96. data/test/functional/associations/test_many_embedded_proxy.rb +256 -0
  97. data/test/functional/associations/test_many_polymorphic_proxy.rb +302 -0
  98. data/test/functional/associations/test_one_embedded_proxy.rb +81 -0
  99. data/test/functional/associations/test_one_proxy.rb +181 -0
  100. data/test/functional/test_accessible.rb +168 -0
  101. data/test/functional/test_associations.rb +44 -0
  102. data/test/functional/test_binary.rb +27 -0
  103. data/test/functional/test_caching.rb +76 -0
  104. data/test/functional/test_callbacks.rb +151 -0
  105. data/test/functional/test_dirty.rb +163 -0
  106. data/test/functional/test_document.rb +253 -0
  107. data/test/functional/test_dynamic_querying.rb +75 -0
  108. data/test/functional/test_embedded_document.rb +210 -0
  109. data/test/functional/test_identity_map.rb +514 -0
  110. data/test/functional/test_indexes.rb +42 -0
  111. data/test/functional/test_logger.rb +20 -0
  112. data/test/functional/test_modifiers.rb +416 -0
  113. data/test/functional/test_pagination.rb +91 -0
  114. data/test/functional/test_protected.rb +175 -0
  115. data/test/functional/test_querying.rb +873 -0
  116. data/test/functional/test_safe.rb +76 -0
  117. data/test/functional/test_sci.rb +230 -0
  118. data/test/functional/test_scopes.rb +171 -0
  119. data/test/functional/test_string_id_compatibility.rb +67 -0
  120. data/test/functional/test_timestamps.rb +62 -0
  121. data/test/functional/test_userstamps.rb +27 -0
  122. data/test/functional/test_validations.rb +342 -0
  123. data/test/models.rb +233 -0
  124. data/test/test_active_model_lint.rb +13 -0
  125. data/test/test_helper.rb +100 -0
  126. data/test/unit/associations/test_base.rb +212 -0
  127. data/test/unit/associations/test_proxy.rb +105 -0
  128. data/test/unit/serializers/test_json_serializer.rb +217 -0
  129. data/test/unit/test_clone.rb +69 -0
  130. data/test/unit/test_descendant_appends.rb +71 -0
  131. data/test/unit/test_document.rb +213 -0
  132. data/test/unit/test_dynamic_finder.rb +125 -0
  133. data/test/unit/test_embedded_document.rb +644 -0
  134. data/test/unit/test_extensions.rb +376 -0
  135. data/test/unit/test_key.rb +185 -0
  136. data/test/unit/test_keys.rb +89 -0
  137. data/test/unit/test_mongo_mapper.rb +110 -0
  138. data/test/unit/test_pagination.rb +11 -0
  139. data/test/unit/test_plugins.rb +50 -0
  140. data/test/unit/test_rails.rb +181 -0
  141. data/test/unit/test_rails_compatibility.rb +52 -0
  142. data/test/unit/test_serialization.rb +51 -0
  143. data/test/unit/test_time_zones.rb +39 -0
  144. data/test/unit/test_validations.rb +564 -0
  145. metadata +337 -0
@@ -0,0 +1,32 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Sci
5
+ module ClassMethods
6
+ def inherited(subclass)
7
+ key :_type, String unless key?(:_type)
8
+ subclass.instance_variable_set("@single_collection_inherited", true)
9
+ subclass.set_collection_name(collection_name) unless subclass.embeddable?
10
+ super
11
+ end
12
+
13
+ def single_collection_inherited?
14
+ @single_collection_inherited == true
15
+ end
16
+
17
+ def query(options={})
18
+ super.tap do |query|
19
+ query[:_type] = name if single_collection_inherited?
20
+ end
21
+ end
22
+ end
23
+
24
+ module InstanceMethods
25
+ def initialize(*args)
26
+ super
27
+ write_key :_type, self.class.name if self.class.key?(:_type)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Scopes
5
+ module ClassMethods
6
+ def scope(name, scope_options={})
7
+ scopes[name] = lambda do |*args|
8
+ result = scope_options.is_a?(Proc) ? scope_options.call(*args) : scope_options
9
+ result = self.query(result) if result.is_a?(Hash)
10
+ self.query.merge(result)
11
+ end
12
+ singleton_class.send :define_method, name, &scopes[name]
13
+ end
14
+
15
+ def scopes
16
+ read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,76 @@
1
+ # encoding: UTF-8
2
+ require 'active_support/json'
3
+
4
+ module MongoMapper
5
+ module Plugins
6
+ module Serialization
7
+ def self.configure(model)
8
+ model.class_eval { cattr_accessor :include_root_in_json, :instance_writer => true }
9
+ end
10
+
11
+ module InstanceMethods
12
+ def as_json options={}
13
+ options ||= {}
14
+ unless options[:only]
15
+ methods = [options.delete(:methods)].flatten.compact
16
+ methods << :id
17
+ options[:methods] = methods.uniq
18
+ end
19
+
20
+ except = [options.delete(:except)].flatten.compact
21
+ except << :_id
22
+ options[:except] = except
23
+
24
+ # Direct rip from Rails 3 ActiveModel Serialization (#serializable_hash)
25
+ hash = begin
26
+ options[:only] = Array.wrap(options[:only]).map { |n| n.to_s }
27
+ options[:except] = Array.wrap(options[:except]).map { |n| n.to_s }
28
+
29
+ attribute_names = attributes.keys.sort
30
+ if options[:only].any?
31
+ attribute_names &= options[:only]
32
+ elsif options[:except].any?
33
+ attribute_names -= options[:except]
34
+ end
35
+
36
+ method_names = Array.wrap(options[:methods]).inject([]) do |methods, name|
37
+ methods << name if respond_to?(name.to_s)
38
+ methods
39
+ end
40
+
41
+ (attribute_names + method_names).inject({}) { |hash, name|
42
+ hash[name] = send(name)
43
+ hash
44
+ }
45
+ end
46
+ # End rip
47
+
48
+ options.delete(:only) if options[:only].nil? or options[:only].empty?
49
+
50
+ hash.each do |key, value|
51
+ if value.is_a?(Array)
52
+ hash[key] = value.map do |item|
53
+ item.respond_to?(:as_json) ? item.as_json(options) : item
54
+ end
55
+ elsif value.is_a? BSON::ObjectId
56
+ hash[key] = value.to_s
57
+ elsif value.respond_to?(:as_json)
58
+ hash[key] = value.as_json(options)
59
+ end
60
+ end
61
+
62
+ # Replicate Rails 3 naming - and also bin anytihng after : for use in our dynamic classes from unit tests
63
+ hash = { ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self.class.name)).gsub(/:.*/,'') => hash } if include_root_in_json
64
+ hash
65
+ end
66
+ end
67
+
68
+ module ClassMethods
69
+ def from_json(json)
70
+ self.new(ActiveSupport::JSON.decode(json))
71
+ end
72
+ end
73
+
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Timestamps
5
+ module ClassMethods
6
+ def timestamps!
7
+ key :created_at, Time
8
+ key :updated_at, Time
9
+ class_eval { before_save :update_timestamps }
10
+ end
11
+ end
12
+
13
+ module InstanceMethods
14
+ def update_timestamps
15
+ now = Time.now.utc
16
+ self[:created_at] = now if new? && !created_at?
17
+ self[:updated_at] = now
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Userstamps
5
+ module ClassMethods
6
+ def userstamps!
7
+ key :creator_id, ObjectId
8
+ key :updater_id, ObjectId
9
+ belongs_to :creator, :class_name => 'User'
10
+ belongs_to :updater, :class_name => 'User'
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Validations
5
+ def self.configure(model)
6
+ model.class_eval do
7
+ include Validatable
8
+ extend Validations::DocumentMacros
9
+ end
10
+ end
11
+
12
+ module DocumentMacros
13
+ def validates_uniqueness_of(*args)
14
+ add_validations(args, Validations::ValidatesUniquenessOf)
15
+ end
16
+ end
17
+
18
+ class ValidatesUniquenessOf < Validatable::ValidationBase
19
+ option :scope, :case_sensitive
20
+ default :case_sensitive => true
21
+
22
+ def valid?(instance)
23
+ value = instance[attribute]
24
+ return allow_nil if value.nil? and not allow_nil.nil?
25
+ return allow_blank if value.blank? and not allow_blank.nil?
26
+ base_conditions = case_sensitive ? {self.attribute => value} : {}
27
+ doc = instance.class.first(base_conditions.merge(scope_conditions(instance)).merge(where_conditions(instance)))
28
+ doc.nil? || instance._id == doc._id
29
+ end
30
+
31
+ def message(instance)
32
+ super || "has already been taken"
33
+ end
34
+
35
+ def scope_conditions(instance)
36
+ return {} unless scope
37
+ Array(scope).inject({}) do |conditions, key|
38
+ conditions.merge(key => instance[key])
39
+ end
40
+ end
41
+
42
+ def where_conditions(instance)
43
+ conditions = {}
44
+ conditions[attribute] = /^#{Regexp.escape(instance[attribute].to_s)}$/i unless case_sensitive
45
+ conditions
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,45 @@
1
+ # encoding: UTF-8
2
+ require 'set'
3
+
4
+ module MongoMapper
5
+ module Support
6
+ module DescendantAppends
7
+ def included(model)
8
+ extra_extensions.each { |extension| model.extend(extension) }
9
+ extra_inclusions.each { |inclusion| model.send(:include, inclusion) }
10
+ descendants << model
11
+ end
12
+
13
+ # @api public
14
+ def descendants
15
+ @descendants ||= Set.new
16
+ end
17
+
18
+ # @api public
19
+ def append_extensions(*extensions)
20
+ extra_extensions.concat(extensions)
21
+ descendants.each do |model|
22
+ extensions.each { |extension| model.extend(extension) }
23
+ end
24
+ end
25
+
26
+ # @api public
27
+ def append_inclusions(*inclusions)
28
+ extra_inclusions.concat(inclusions)
29
+ descendants.each do |model|
30
+ inclusions.each { |inclusion| model.send(:include, inclusion) }
31
+ end
32
+ end
33
+
34
+ # @api private
35
+ def extra_extensions
36
+ @extra_extensions ||= []
37
+ end
38
+
39
+ # @api private
40
+ def extra_inclusions
41
+ @extra_inclusions ||= []
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,4 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ Version = '0.8.6'
4
+ end
data/rails/init.rb ADDED
@@ -0,0 +1,19 @@
1
+ # See http://groups.google.com/group/mongomapper/browse_thread/thread/68f62e8eda43b43a/4841dba76938290c
2
+ #
3
+ # This is only for development mode. You will still want to clear the identity map before each request in production.
4
+ # See examples/identity_map for more on this.
5
+ #
6
+ # to_prepare is called before each request in development mode and the first request in production.
7
+ Rails.configuration.to_prepare do
8
+ if Rails.configuration.cache_classes
9
+ MongoMapper::Plugins::IdentityMap.clear
10
+ else
11
+ # Rails reloading was making descendants fill up and leak memory, these make sure they get cleared
12
+ MongoMapper::Document.descendants.each {|m| m.descendants.clear if m.respond_to?(:descendants) }
13
+ MongoMapper::Document.descendants.clear
14
+ MongoMapper::EmbeddedDocument.descendants.each {|m| m.descendants.clear if m.respond_to?(:descendants) }
15
+ MongoMapper::EmbeddedDocument.descendants.clear
16
+ MongoMapper::Plugins::IdentityMap.clear
17
+ MongoMapper::Plugins::IdentityMap.models.clear
18
+ end
19
+ end
@@ -0,0 +1 @@
1
+ I am doing my best to keep unit and functional tests separate. As I see them, functional tests hit the database and should never care about internals. Unit tests do not hit the database.
@@ -0,0 +1,63 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class BelongsToPolymorphicProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ Status.collection.remove
7
+ Project.collection.remove
8
+ end
9
+
10
+ should "default to nil" do
11
+ status = Status.new
12
+ status.target.nil?.should be_true
13
+ status.target.inspect.should == "nil"
14
+ end
15
+
16
+ should "have boolean presence method" do
17
+ status = Status.new
18
+ status.target?.should be_false
19
+
20
+ status.target = Project.new(:name => 'mongomapper')
21
+ status.target?.should be_true
22
+ end
23
+
24
+ should "be able to replace the association" do
25
+ status = Status.new(:name => 'Foo!')
26
+ project = Project.new(:name => "mongomapper")
27
+ status.target = project
28
+ status.save.should be_true
29
+
30
+ status = status.reload
31
+ status.target.nil?.should be_false
32
+ status.target_id.should == project._id
33
+ status.target_type.should == "Project"
34
+ status.target.name.should == "mongomapper"
35
+ end
36
+
37
+ should "unset the association" do
38
+ status = Status.new(:name => 'Foo!')
39
+ project = Project.new(:name => "mongomapper")
40
+ status.target = project
41
+ status.save.should be_true
42
+
43
+ status = status.reload
44
+ status.target = nil
45
+ status.target_type.nil?.should be_true
46
+ status.target_id.nil?.should be_true
47
+ status.target.nil?.should be_true
48
+ end
49
+
50
+ context "association id set but document not found" do
51
+ setup do
52
+ @status = Status.new(:name => 'Foo!')
53
+ project = Project.new(:name => "mongomapper")
54
+ @status.target = project
55
+ @status.save.should be_true
56
+ project.destroy
57
+ end
58
+
59
+ should "return nil instead of raising error" do
60
+ @status.target.nil?.should be_true
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,93 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class BelongsToProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ @post_class = Doc()
7
+ @comment_class = Doc do
8
+ key :post_id, String
9
+ end
10
+
11
+ @comment_class.belongs_to :post, :class => @post_class
12
+ end
13
+
14
+ should "default to nil" do
15
+ @comment_class.new.post.nil?.should be_true
16
+ end
17
+
18
+ should "have boolean presence method" do
19
+ comment = @comment_class.new(:name => 'Foo!')
20
+ comment.post?.should be_false
21
+
22
+ comment.post = @post_class.new(:name => 'mongomapper')
23
+ comment.post?.should be_true
24
+ end
25
+
26
+ should "be able to replace the association" do
27
+ post = @post_class.new(:name => 'mongomapper')
28
+ comment = @comment_class.new(:name => 'Foo!', :post => post)
29
+ comment.save.should be_true
30
+
31
+ comment = comment.reload
32
+ comment.post.should == post
33
+ comment.post.nil?.should be_false
34
+ end
35
+
36
+ should "unset the association" do
37
+ post = @post_class.new(:name => 'mongomapper')
38
+ comment = @comment_class.new(:name => 'Foo!', :post => post)
39
+ comment.save.should be_true
40
+
41
+ comment = comment.reload
42
+ comment.post = nil
43
+ comment.post.nil?.should be_true
44
+ end
45
+
46
+ should "return nil if id set but document not found" do
47
+ id = BSON::ObjectId.new
48
+ @comment_class.new(:name => 'Foo', :post_id => id).post.nil?.should be_true
49
+ end
50
+
51
+ context ":dependent" do
52
+ setup do
53
+ # FIXME: make use of already defined models
54
+ class ::Property
55
+ include MongoMapper::Document
56
+ end
57
+ Property.collection.remove
58
+
59
+ class ::Thing
60
+ include MongoMapper::Document
61
+ key :name, String
62
+ end
63
+ Thing.collection.remove
64
+ end
65
+
66
+ teardown do
67
+ Object.send :remove_const, 'Property' if defined?(::Property)
68
+ Object.send :remove_const, 'Thing' if defined?(::Thing)
69
+ end
70
+
71
+ context "=> destroy" do
72
+ setup do
73
+ Property.key :thing_id, ObjectId
74
+ Property.belongs_to :thing, :dependent => :destroy
75
+ Thing.many :properties
76
+
77
+ @thing = Thing.create(:name => "Tree")
78
+ @property1 = Property.create
79
+ @property2 = Property.create
80
+ @property3 = Property.create
81
+ @thing.properties << @property1
82
+ @thing.properties << @property2
83
+ @thing.properties << @property3
84
+ end
85
+
86
+ should "not execute on a belongs_to association" do
87
+ Thing.count.should == 1
88
+ @property1.destroy
89
+ Thing.count.should == 1
90
+ end
91
+ end
92
+ end
93
+ end