mongoid 1.2.14 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (200) hide show
  1. data/lib/mongoid.rb +10 -3
  2. data/lib/mongoid/associations.rb +133 -97
  3. data/lib/mongoid/associations/belongs_to_related.rb +2 -3
  4. data/lib/mongoid/associations/{belongs_to.rb → embedded_in.rb} +14 -6
  5. data/lib/mongoid/associations/{has_many.rb → embeds_many.rb} +89 -31
  6. data/lib/mongoid/associations/{has_one.rb → embeds_one.rb} +8 -7
  7. data/lib/mongoid/associations/has_many_related.rb +52 -7
  8. data/lib/mongoid/associations/has_one_related.rb +8 -4
  9. data/lib/mongoid/associations/meta_data.rb +2 -1
  10. data/lib/mongoid/associations/options.rb +6 -1
  11. data/lib/mongoid/associations/proxy.rb +14 -21
  12. data/lib/mongoid/attributes.rb +27 -12
  13. data/lib/mongoid/collection.rb +4 -3
  14. data/lib/mongoid/collections.rb +41 -0
  15. data/lib/mongoid/collections/master.rb +3 -2
  16. data/lib/mongoid/collections/slaves.rb +3 -2
  17. data/lib/mongoid/components.rb +21 -19
  18. data/lib/mongoid/concern.rb +31 -0
  19. data/lib/mongoid/config.rb +117 -12
  20. data/lib/mongoid/contexts.rb +1 -1
  21. data/lib/mongoid/contexts/enumerable.rb +1 -1
  22. data/lib/mongoid/contexts/mongo.rb +1 -1
  23. data/lib/mongoid/contexts/paging.rb +10 -2
  24. data/lib/mongoid/criterion/inclusion.rb +17 -0
  25. data/lib/mongoid/criterion/optional.rb +1 -1
  26. data/lib/mongoid/dirty.rb +253 -0
  27. data/lib/mongoid/document.rb +81 -52
  28. data/lib/mongoid/errors.rb +32 -1
  29. data/lib/mongoid/extensions.rb +11 -9
  30. data/lib/mongoid/extensions/big_decimal/conversions.rb +2 -2
  31. data/lib/mongoid/extensions/boolean/conversions.rb +8 -2
  32. data/lib/mongoid/extensions/date/conversions.rb +13 -4
  33. data/lib/mongoid/extensions/datetime/conversions.rb +1 -6
  34. data/lib/mongoid/extensions/float/conversions.rb +5 -1
  35. data/lib/mongoid/extensions/hash/assimilation.rb +12 -3
  36. data/lib/mongoid/extensions/hash/conversions.rb +34 -4
  37. data/lib/mongoid/extensions/integer/conversions.rb +5 -1
  38. data/lib/mongoid/extensions/nil/assimilation.rb +4 -0
  39. data/lib/mongoid/extensions/object/conversions.rb +1 -1
  40. data/lib/mongoid/extensions/string/conversions.rb +1 -1
  41. data/lib/mongoid/extensions/symbol/inflections.rb +1 -1
  42. data/lib/mongoid/extensions/time_conversions.rb +35 -0
  43. data/lib/mongoid/extras.rb +6 -9
  44. data/lib/mongoid/factory.rb +2 -1
  45. data/lib/mongoid/field.rb +9 -2
  46. data/lib/mongoid/fields.rb +1 -0
  47. data/lib/mongoid/identity.rb +3 -3
  48. data/lib/mongoid/indexes.rb +3 -3
  49. data/lib/mongoid/memoization.rb +8 -2
  50. data/lib/mongoid/named_scope.rb +0 -3
  51. data/lib/mongoid/observable.rb +30 -0
  52. data/lib/mongoid/paths.rb +62 -0
  53. data/lib/mongoid/persistence.rb +222 -0
  54. data/lib/mongoid/persistence/command.rb +39 -0
  55. data/lib/mongoid/persistence/insert.rb +50 -0
  56. data/lib/mongoid/persistence/insert_embedded.rb +38 -0
  57. data/lib/mongoid/persistence/remove.rb +39 -0
  58. data/lib/mongoid/persistence/remove_all.rb +37 -0
  59. data/lib/mongoid/persistence/remove_embedded.rb +50 -0
  60. data/lib/mongoid/persistence/update.rb +63 -0
  61. data/lib/mongoid/state.rb +28 -21
  62. data/lib/mongoid/timestamps.rb +5 -8
  63. data/lib/mongoid/version.rb +4 -0
  64. data/lib/mongoid/versioning.rb +6 -7
  65. metadata +81 -300
  66. data/.gitignore +0 -6
  67. data/.watchr +0 -29
  68. data/Rakefile +0 -53
  69. data/VERSION +0 -1
  70. data/caliper.yml +0 -4
  71. data/lib/mongoid/collections/mimic.rb +0 -46
  72. data/lib/mongoid/commands.rb +0 -174
  73. data/lib/mongoid/commands/create.rb +0 -21
  74. data/lib/mongoid/commands/delete.rb +0 -16
  75. data/lib/mongoid/commands/delete_all.rb +0 -23
  76. data/lib/mongoid/commands/deletion.rb +0 -18
  77. data/lib/mongoid/commands/destroy.rb +0 -19
  78. data/lib/mongoid/commands/destroy_all.rb +0 -23
  79. data/lib/mongoid/commands/save.rb +0 -27
  80. data/lib/mongoid/extensions/time/conversions.rb +0 -18
  81. data/mongoid.gemspec +0 -395
  82. data/perf/benchmark.rb +0 -77
  83. data/spec/integration/mongoid/associations_spec.rb +0 -340
  84. data/spec/integration/mongoid/attributes_spec.rb +0 -22
  85. data/spec/integration/mongoid/commands_spec.rb +0 -218
  86. data/spec/integration/mongoid/contexts/enumerable_spec.rb +0 -33
  87. data/spec/integration/mongoid/criteria_spec.rb +0 -272
  88. data/spec/integration/mongoid/document_spec.rb +0 -593
  89. data/spec/integration/mongoid/extensions_spec.rb +0 -26
  90. data/spec/integration/mongoid/finders_spec.rb +0 -119
  91. data/spec/integration/mongoid/inheritance_spec.rb +0 -137
  92. data/spec/integration/mongoid/named_scope_spec.rb +0 -46
  93. data/spec/models/address.rb +0 -39
  94. data/spec/models/animal.rb +0 -6
  95. data/spec/models/callbacks.rb +0 -18
  96. data/spec/models/comment.rb +0 -8
  97. data/spec/models/country_code.rb +0 -6
  98. data/spec/models/employer.rb +0 -5
  99. data/spec/models/game.rb +0 -7
  100. data/spec/models/inheritance.rb +0 -56
  101. data/spec/models/location.rb +0 -5
  102. data/spec/models/mixed_drink.rb +0 -4
  103. data/spec/models/name.rb +0 -13
  104. data/spec/models/namespacing.rb +0 -11
  105. data/spec/models/patient.rb +0 -4
  106. data/spec/models/person.rb +0 -99
  107. data/spec/models/pet.rb +0 -7
  108. data/spec/models/pet_owner.rb +0 -6
  109. data/spec/models/phone.rb +0 -7
  110. data/spec/models/post.rb +0 -15
  111. data/spec/models/translation.rb +0 -5
  112. data/spec/models/vet_visit.rb +0 -5
  113. data/spec/spec.opts +0 -3
  114. data/spec/spec_helper.rb +0 -31
  115. data/spec/unit/mongoid/associations/belongs_to_related_spec.rb +0 -145
  116. data/spec/unit/mongoid/associations/belongs_to_spec.rb +0 -193
  117. data/spec/unit/mongoid/associations/has_many_related_spec.rb +0 -420
  118. data/spec/unit/mongoid/associations/has_many_spec.rb +0 -519
  119. data/spec/unit/mongoid/associations/has_one_related_spec.rb +0 -179
  120. data/spec/unit/mongoid/associations/has_one_spec.rb +0 -282
  121. data/spec/unit/mongoid/associations/meta_data_spec.rb +0 -88
  122. data/spec/unit/mongoid/associations/options_spec.rb +0 -192
  123. data/spec/unit/mongoid/associations_spec.rb +0 -595
  124. data/spec/unit/mongoid/attributes_spec.rb +0 -507
  125. data/spec/unit/mongoid/callbacks_spec.rb +0 -55
  126. data/spec/unit/mongoid/collection_spec.rb +0 -187
  127. data/spec/unit/mongoid/collections/cyclic_iterator_spec.rb +0 -75
  128. data/spec/unit/mongoid/collections/master_spec.rb +0 -41
  129. data/spec/unit/mongoid/collections/mimic_spec.rb +0 -43
  130. data/spec/unit/mongoid/collections/slaves_spec.rb +0 -81
  131. data/spec/unit/mongoid/commands/create_spec.rb +0 -30
  132. data/spec/unit/mongoid/commands/delete_all_spec.rb +0 -58
  133. data/spec/unit/mongoid/commands/delete_spec.rb +0 -38
  134. data/spec/unit/mongoid/commands/destroy_all_spec.rb +0 -23
  135. data/spec/unit/mongoid/commands/destroy_spec.rb +0 -50
  136. data/spec/unit/mongoid/commands/save_spec.rb +0 -105
  137. data/spec/unit/mongoid/commands_spec.rb +0 -275
  138. data/spec/unit/mongoid/config_spec.rb +0 -172
  139. data/spec/unit/mongoid/contexts/enumerable_spec.rb +0 -421
  140. data/spec/unit/mongoid/contexts/mongo_spec.rb +0 -682
  141. data/spec/unit/mongoid/contexts_spec.rb +0 -25
  142. data/spec/unit/mongoid/criteria_spec.rb +0 -824
  143. data/spec/unit/mongoid/criterion/complex_spec.rb +0 -19
  144. data/spec/unit/mongoid/criterion/exclusion_spec.rb +0 -91
  145. data/spec/unit/mongoid/criterion/inclusion_spec.rb +0 -219
  146. data/spec/unit/mongoid/criterion/optional_spec.rb +0 -319
  147. data/spec/unit/mongoid/cursor_spec.rb +0 -74
  148. data/spec/unit/mongoid/deprecation_spec.rb +0 -24
  149. data/spec/unit/mongoid/document_spec.rb +0 -952
  150. data/spec/unit/mongoid/errors_spec.rb +0 -103
  151. data/spec/unit/mongoid/extensions/array/accessors_spec.rb +0 -50
  152. data/spec/unit/mongoid/extensions/array/assimilation_spec.rb +0 -24
  153. data/spec/unit/mongoid/extensions/array/conversions_spec.rb +0 -35
  154. data/spec/unit/mongoid/extensions/array/parentization_spec.rb +0 -20
  155. data/spec/unit/mongoid/extensions/big_decimal/conversions_spec.rb +0 -22
  156. data/spec/unit/mongoid/extensions/binary/conversions_spec.rb +0 -22
  157. data/spec/unit/mongoid/extensions/boolean/conversions_spec.rb +0 -49
  158. data/spec/unit/mongoid/extensions/date/conversions_spec.rb +0 -102
  159. data/spec/unit/mongoid/extensions/datetime/conversions_spec.rb +0 -70
  160. data/spec/unit/mongoid/extensions/float/conversions_spec.rb +0 -61
  161. data/spec/unit/mongoid/extensions/hash/accessors_spec.rb +0 -184
  162. data/spec/unit/mongoid/extensions/hash/assimilation_spec.rb +0 -46
  163. data/spec/unit/mongoid/extensions/hash/conversions_spec.rb +0 -21
  164. data/spec/unit/mongoid/extensions/hash/criteria_helpers_spec.rb +0 -17
  165. data/spec/unit/mongoid/extensions/hash/scoping_spec.rb +0 -14
  166. data/spec/unit/mongoid/extensions/integer/conversions_spec.rb +0 -61
  167. data/spec/unit/mongoid/extensions/nil/assimilation_spec.rb +0 -24
  168. data/spec/unit/mongoid/extensions/object/conversions_spec.rb +0 -57
  169. data/spec/unit/mongoid/extensions/proc/scoping_spec.rb +0 -34
  170. data/spec/unit/mongoid/extensions/string/conversions_spec.rb +0 -17
  171. data/spec/unit/mongoid/extensions/string/inflections_spec.rb +0 -208
  172. data/spec/unit/mongoid/extensions/symbol/inflections_spec.rb +0 -91
  173. data/spec/unit/mongoid/extensions/time/conversions_spec.rb +0 -70
  174. data/spec/unit/mongoid/extras_spec.rb +0 -102
  175. data/spec/unit/mongoid/factory_spec.rb +0 -31
  176. data/spec/unit/mongoid/field_spec.rb +0 -143
  177. data/spec/unit/mongoid/fields_spec.rb +0 -181
  178. data/spec/unit/mongoid/finders_spec.rb +0 -404
  179. data/spec/unit/mongoid/identity_spec.rb +0 -109
  180. data/spec/unit/mongoid/indexes_spec.rb +0 -93
  181. data/spec/unit/mongoid/javascript_spec.rb +0 -48
  182. data/spec/unit/mongoid/matchers/all_spec.rb +0 -27
  183. data/spec/unit/mongoid/matchers/default_spec.rb +0 -27
  184. data/spec/unit/mongoid/matchers/exists_spec.rb +0 -56
  185. data/spec/unit/mongoid/matchers/gt_spec.rb +0 -39
  186. data/spec/unit/mongoid/matchers/gte_spec.rb +0 -49
  187. data/spec/unit/mongoid/matchers/in_spec.rb +0 -27
  188. data/spec/unit/mongoid/matchers/lt_spec.rb +0 -39
  189. data/spec/unit/mongoid/matchers/lte_spec.rb +0 -49
  190. data/spec/unit/mongoid/matchers/ne_spec.rb +0 -27
  191. data/spec/unit/mongoid/matchers/nin_spec.rb +0 -27
  192. data/spec/unit/mongoid/matchers/size_spec.rb +0 -27
  193. data/spec/unit/mongoid/matchers_spec.rb +0 -329
  194. data/spec/unit/mongoid/memoization_spec.rb +0 -75
  195. data/spec/unit/mongoid/named_scope_spec.rb +0 -123
  196. data/spec/unit/mongoid/scope_spec.rb +0 -240
  197. data/spec/unit/mongoid/state_spec.rb +0 -83
  198. data/spec/unit/mongoid/timestamps_spec.rb +0 -25
  199. data/spec/unit/mongoid/versioning_spec.rb +0 -41
  200. data/spec/unit/mongoid_spec.rb +0 -46
@@ -22,12 +22,12 @@
22
22
  require "rubygems"
23
23
 
24
24
  gem "activesupport", ">= 2.2.2", "<3.0.pre"
25
- gem "mongo", ">= 0.19.1"
25
+ gem "mongo", "~>1.0"
26
+ gem "bson", "~>1.0"
26
27
  gem "durran-validatable", ">= 2.0.1"
27
28
  gem "will_paginate", ">= 2.3.11", "< 2.9"
28
29
 
29
30
  require "delegate"
30
- require "observer"
31
31
  require "singleton"
32
32
  require "time"
33
33
  require "validatable"
@@ -37,16 +37,19 @@ require "active_support/inflector"
37
37
  require "active_support/time_with_zone"
38
38
  require "will_paginate/collection"
39
39
  require "mongo"
40
+ require "mongoid/concern"
41
+ require "mongoid/observable"
40
42
  require "mongoid/associations"
41
43
  require "mongoid/attributes"
42
44
  require "mongoid/callbacks"
43
45
  require "mongoid/collection"
44
- require "mongoid/commands"
46
+ require "mongoid/collections"
45
47
  require "mongoid/config"
46
48
  require "mongoid/contexts"
47
49
  require "mongoid/criteria"
48
50
  require "mongoid/cursor"
49
51
  require "mongoid/deprecation"
52
+ require "mongoid/dirty"
50
53
  require "mongoid/extensions"
51
54
  require "mongoid/extras"
52
55
  require "mongoid/errors"
@@ -60,6 +63,8 @@ require "mongoid/javascript"
60
63
  require "mongoid/matchers"
61
64
  require "mongoid/memoization"
62
65
  require "mongoid/named_scope"
66
+ require "mongoid/paths"
67
+ require "mongoid/persistence"
63
68
  require "mongoid/scope"
64
69
  require "mongoid/state"
65
70
  require "mongoid/timestamps"
@@ -69,6 +74,8 @@ require "mongoid/document"
69
74
 
70
75
  module Mongoid #:nodoc
71
76
 
77
+ MONGODB_VERSION = "1.4.0"
78
+
72
79
  class << self
73
80
 
74
81
  # Sets the Mongoid configuration options. Best used by passing a block.
@@ -1,25 +1,25 @@
1
1
  # encoding: utf-8
2
2
  require "mongoid/associations/proxy"
3
- require "mongoid/associations/belongs_to"
4
3
  require "mongoid/associations/belongs_to_related"
5
- require "mongoid/associations/has_many"
4
+ require "mongoid/associations/embedded_in"
5
+ require "mongoid/associations/embeds_many"
6
+ require "mongoid/associations/embeds_one"
6
7
  require "mongoid/associations/has_many_related"
7
- require "mongoid/associations/has_one"
8
8
  require "mongoid/associations/has_one_related"
9
9
  require "mongoid/associations/options"
10
10
  require "mongoid/associations/meta_data"
11
11
 
12
12
  module Mongoid # :nodoc:
13
13
  module Associations #:nodoc:
14
- def self.included(base)
15
- base.class_eval do
16
- # Associations need to inherit down the chain.
17
- class_inheritable_accessor :associations
18
- self.associations = {}
14
+ extend ActiveSupport::Concern
15
+ included do
16
+ cattr_accessor :embedded
17
+ self.embedded = false
19
18
 
20
- include InstanceMethods
21
- extend ClassMethods
22
- end
19
+ class_inheritable_accessor :associations
20
+ self.associations = {}
21
+
22
+ delegate :embedded, :embedded?, :to => "self.class"
23
23
  end
24
24
 
25
25
  module InstanceMethods
@@ -28,9 +28,15 @@ module Mongoid # :nodoc:
28
28
  self.class.associations
29
29
  end
30
30
 
31
- # Updates all the one-to-many relational associations for the name.
32
- def update_associations(name)
33
- send(name).each { |doc| doc.save } if new_record?
31
+ # are we in an embeds_many?
32
+ def embedded_many?
33
+ embedded? and _parent.associations[association_name].association == EmbedsMany
34
+ end
35
+
36
+ # Update all the dirty child documents after an update.
37
+ def update_embedded(name)
38
+ association = send(name)
39
+ association.to_a.each { |doc| doc.save if doc.changed? || doc.new_record? } unless association.blank?
34
40
  end
35
41
 
36
42
  # Update the one-to-one relational association for the name.
@@ -38,9 +44,48 @@ module Mongoid # :nodoc:
38
44
  association = send(name)
39
45
  association.save if new_record? && !association.nil?
40
46
  end
47
+
48
+ # Updates all the one-to-many relational associations for the name.
49
+ def update_associations(name)
50
+ send(name).each { |doc| doc.save } if new_record?
51
+ end
41
52
  end
42
53
 
43
54
  module ClassMethods
55
+ # Adds a relational association from the child Document to a Document in
56
+ # another database or collection.
57
+ #
58
+ # Options:
59
+ #
60
+ # name: A +Symbol+ that is the related class name.
61
+ #
62
+ # Example:
63
+ #
64
+ # class Game
65
+ # include Mongoid::Document
66
+ # belongs_to_related :person
67
+ # end
68
+ #
69
+ def belongs_to_related(name, options = {}, &block)
70
+ opts = optionize(name, options, fk(name, options), &block)
71
+ associate(Associations::BelongsToRelated, opts)
72
+ field(opts.foreign_key, :type => Mongoid.use_object_ids ? BSON::ObjectID : String)
73
+ index(opts.foreign_key) unless embedded?
74
+ end
75
+
76
+ # Gets whether or not the document is embedded.
77
+ #
78
+ # Example:
79
+ #
80
+ # <tt>Person.embedded?</tt>
81
+ #
82
+ # Returns:
83
+ #
84
+ # <tt>true</tt> if embedded, <tt>false</tt> if not.
85
+ def embedded?
86
+ !!self.embedded
87
+ end
88
+
44
89
  # Adds the association back to the parent document. This macro is
45
90
  # necessary to set the references from the child back to the parent
46
91
  # document. If a child does not define this association calling
@@ -54,51 +99,56 @@ module Mongoid # :nodoc:
54
99
  #
55
100
  # class Person
56
101
  # include Mongoid::Document
57
- # has_many :addresses
102
+ # embeds_many :addresses
58
103
  # end
59
104
  #
60
105
  # class Address
61
106
  # include Mongoid::Document
62
- # belongs_to :person, :inverse_of => :addresses
107
+ # embedded_in :person, :inverse_of => :addresses
63
108
  # end
64
- def belongs_to(name, options = {}, &block)
109
+ def embedded_in(name, options = {}, &block)
65
110
  unless options.has_key?(:inverse_of)
66
- raise Errors::InvalidOptions.new("Options for belongs_to association must include :inverse_of")
111
+ raise Errors::InvalidOptions.new("Options for embedded_in association must include :inverse_of")
67
112
  end
68
113
  self.embedded = true
69
- add_association(
70
- Associations::BelongsTo,
71
- Associations::Options.new(
72
- options.merge(:name => name, :extend => block)
73
- )
74
- )
114
+ associate(Associations::EmbeddedIn, optionize(name, options, nil, &block))
75
115
  end
76
116
 
77
- # Adds a relational association from the child Document to a Document in
78
- # another database or collection.
117
+ alias :belongs_to :embedded_in
118
+
119
+ # Adds the association from a parent document to its children. The name
120
+ # of the association needs to be a pluralized form of the child class
121
+ # name.
79
122
  #
80
123
  # Options:
81
124
  #
82
- # name: A +Symbol+ that is the related class name.
125
+ # name: A +Symbol+ that is the plural child class name.
83
126
  #
84
127
  # Example:
85
128
  #
86
- # class Game
129
+ # class Person
87
130
  # include Mongoid::Document
88
- # belongs_to_related :person
131
+ # embeds_many :addresses
89
132
  # end
90
133
  #
91
- def belongs_to_related(name, options = {}, &block)
92
- opts = Associations::Options.new(
93
- options.merge(:name => name, :extend => block, :foreign_key => foreign_key(name, options))
94
- )
95
- add_association(Associations::BelongsToRelated, opts)
96
- field(opts.foreign_key, :type => Mongoid.use_object_ids ? Mongo::ObjectID : String)
97
- index(opts.foreign_key) unless self.embedded
134
+ # class Address
135
+ # include Mongoid::Document
136
+ # embedded_in :person, :inverse_of => :addresses
137
+ # end
138
+ def embeds_many(name, options = {}, &block)
139
+ associate(Associations::EmbedsMany, optionize(name, options, nil, &block))
140
+ unless name == :versions
141
+ after_update do |document|
142
+ document.update_embedded(name)
143
+ end
144
+ end
98
145
  end
99
146
 
100
- # Adds the association from a parent document to its children. The name
101
- # of the association needs to be a pluralized form of the child class
147
+ alias :embed_many :embeds_many
148
+ alias :has_many :embeds_many
149
+
150
+ # Adds the association from a parent document to its child. The name
151
+ # of the association needs to be a singular form of the child class
102
152
  # name.
103
153
  #
104
154
  # Options:
@@ -109,22 +159,27 @@ module Mongoid # :nodoc:
109
159
  #
110
160
  # class Person
111
161
  # include Mongoid::Document
112
- # has_many :addresses
162
+ # embeds_one :name
113
163
  # end
114
164
  #
115
- # class Address
165
+ # class Name
116
166
  # include Mongoid::Document
117
- # belongs_to :person, :inverse_of => :addresses
167
+ # embedded_in :person
118
168
  # end
119
- def has_many(name, options = {}, &block)
120
- add_association(
121
- Associations::HasMany,
122
- Associations::Options.new(
123
- options.merge(:name => name, :extend => block)
124
- )
125
- )
169
+ def embeds_one(name, options = {}, &block)
170
+ opts = optionize(name, options, nil, &block)
171
+ type = Associations::EmbedsOne
172
+ associate(type, opts)
173
+ add_builder(type, opts)
174
+ add_creator(type, opts)
175
+ after_update do |document|
176
+ document.update_embedded(name)
177
+ end
126
178
  end
127
179
 
180
+ alias :embed_one :embeds_one
181
+ alias :has_one :embeds_one
182
+
128
183
  # Adds a relational association from the Document to many Documents in
129
184
  # another database or collection.
130
185
  #
@@ -140,45 +195,12 @@ module Mongoid # :nodoc:
140
195
  # end
141
196
  #
142
197
  def has_many_related(name, options = {}, &block)
143
- add_association(Associations::HasManyRelated,
144
- Associations::Options.new(
145
- options.merge(:name => name, :foreign_key => foreign_key(self.name, options), :extend => block)
146
- )
147
- )
198
+ associate(Associations::HasManyRelated, optionize(name, options, fk(self.name, options), &block))
148
199
  before_save do |document|
149
200
  document.update_associations(name)
150
201
  end
151
202
  end
152
203
 
153
- # Adds the association from a parent document to its child. The name
154
- # of the association needs to be a singular form of the child class
155
- # name.
156
- #
157
- # Options:
158
- #
159
- # name: A +Symbol+ that is the plural child class name.
160
- #
161
- # Example:
162
- #
163
- # class Person
164
- # include Mongoid::Document
165
- # has_many :addresses
166
- # end
167
- #
168
- # class Address
169
- # include Mongoid::Document
170
- # belongs_to :person
171
- # end
172
- def has_one(name, options = {}, &block)
173
- opts = Associations::Options.new(
174
- options.merge(:name => name, :extend => block)
175
- )
176
- type = Associations::HasOne
177
- add_association(type, opts)
178
- add_builder(type, opts)
179
- add_creator(type, opts)
180
- end
181
-
182
204
  # Adds a relational association from the Document to one Document in
183
205
  # another database or collection.
184
206
  #
@@ -193,12 +215,7 @@ module Mongoid # :nodoc:
193
215
  # has_one_related :game
194
216
  # end
195
217
  def has_one_related(name, options = {}, &block)
196
- add_association(
197
- Associations::HasOneRelated,
198
- Associations::Options.new(
199
- options.merge(:name => name, :foreign_key => foreign_key(name, options), :extend => block)
200
- )
201
- )
218
+ associate(Associations::HasOneRelated, optionize(name, options, fk(self.name, options), &block))
202
219
  before_save do |document|
203
220
  document.update_association(name)
204
221
  end
@@ -223,14 +240,17 @@ module Mongoid # :nodoc:
223
240
  # Adds the association to the associations hash with the type as the key,
224
241
  # then adds the accessors for the association. The defined setters and
225
242
  # getters for the associations will perform the necessary memoization.
226
- def add_association(type, options)
243
+ #
244
+ # Example:
245
+ #
246
+ # <tt>Person.associate(EmbedsMany, { :name => :addresses })</tt>
247
+ def associate(type, options)
227
248
  name = options.name.to_s
228
249
  associations[name] = MetaData.new(type, options)
229
- define_method(name) do
230
- memoized(name) { type.instantiate(self, options) }
231
- end
250
+ define_method(name) { memoized(name) { type.instantiate(self, options) } }
232
251
  define_method("#{name}=") do |object|
233
- reset(name) { type.update(object, self, options) }
252
+ unmemoize(name)
253
+ memoized(name) { type.update(object, self, options) }
234
254
  end
235
255
  end
236
256
 
@@ -249,16 +269,32 @@ module Mongoid # :nodoc:
249
269
  name = options.name.to_s
250
270
  define_method("create_#{name}") do |attrs|
251
271
  document = send("build_#{name}", attrs)
252
- document.run_callbacks(:before_create)
253
- document.save
254
- document.run_callbacks(:after_create); document
272
+ document.save; document
255
273
  end
256
274
  end
257
275
 
276
+ # build the options given the params.
277
+ def optionize(name, options, foreign_key, &block)
278
+ Associations::Options.new(
279
+ options.merge(:name => name, :foreign_key => foreign_key, :extend => block)
280
+ )
281
+ end
282
+
258
283
  # Find the foreign key.
259
- def foreign_key(name, options)
284
+ def fk(name, options)
260
285
  options[:foreign_key] || name.to_s.foreign_key
261
286
  end
287
+
288
+ # Build the association options.
289
+ def build_options(name, options, &block)
290
+ Associations::Options.new(
291
+ options.merge(
292
+ :name => name,
293
+ :foreign_key => foreign_key(name, options),
294
+ :extend => block
295
+ )
296
+ )
297
+ end
262
298
  end
263
299
  end
264
300
  end
@@ -1,8 +1,8 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid #:nodoc:
3
3
  module Associations #:nodoc:
4
- class BelongsToRelated #:nodoc:
5
- include Proxy
4
+ # Represents a relational association to a "parent" object.
5
+ class BelongsToRelated < Proxy
6
6
 
7
7
  # Initializing a related association only requires looking up the object
8
8
  # by its id.
@@ -53,7 +53,6 @@ module Mongoid #:nodoc:
53
53
  instantiate(document, options, target)
54
54
  end
55
55
  end
56
-
57
56
  end
58
57
  end
59
58
  end
@@ -1,8 +1,9 @@
1
1
  # encoding: utf-8
2
2
  module Mongoid #:nodoc:
3
3
  module Associations #:nodoc:
4
- class BelongsTo #:nodoc:
5
- include Proxy
4
+ # Represents an association that is embedded within another document in the
5
+ # database, either as one or many.
6
+ class EmbeddedIn < Proxy
6
7
 
7
8
  # Creates the new association by setting the internal
8
9
  # target as the passed in Document. This should be the
@@ -43,21 +44,28 @@ module Mongoid #:nodoc:
43
44
 
44
45
  # Returns the macro used to create the association.
45
46
  def macro
46
- :belongs_to
47
+ :embedded_in
47
48
  end
48
49
 
49
50
  # Perform an update of the relationship of the parent and child. This
50
51
  # is initialized by setting a parent object as the association on the
51
- # +Document+. Will properly set a has_one or a has_many.
52
+ # +Document+. Will properly set an embeds_one or an embeds_many.
52
53
  #
53
54
  # Returns:
54
55
  #
55
- # A new +BelongsTo+ association proxy.
56
+ # A new +EmbeddedIn+ association proxy.
56
57
  def update(target, child, options)
57
- child.parentize(target, options.inverse_of)
58
+ child.parentize(target, determine_name(target, options))
58
59
  child.notify
59
60
  instantiate(child, options)
60
61
  end
62
+
63
+ protected
64
+ def determine_name(target, options)
65
+ inverse = options.inverse_of
66
+ return inverse unless inverse.is_a?(Array)
67
+ inverse.detect { |name| target.respond_to?(name) }
68
+ end
61
69
  end
62
70
  end
63
71
  end