mongoid-locomotive 2.0.0.beta9

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 (274) hide show
  1. data/MIT_LICENSE +20 -0
  2. data/README.rdoc +47 -0
  3. data/lib/mongoid.rb +141 -0
  4. data/lib/mongoid/associations.rb +306 -0
  5. data/lib/mongoid/associations/embedded_in.rb +74 -0
  6. data/lib/mongoid/associations/embeds_many.rb +280 -0
  7. data/lib/mongoid/associations/embeds_one.rb +97 -0
  8. data/lib/mongoid/associations/foreign_key.rb +35 -0
  9. data/lib/mongoid/associations/meta_data.rb +38 -0
  10. data/lib/mongoid/associations/options.rb +62 -0
  11. data/lib/mongoid/associations/proxy.rb +33 -0
  12. data/lib/mongoid/associations/referenced_in.rb +59 -0
  13. data/lib/mongoid/associations/references_many.rb +245 -0
  14. data/lib/mongoid/associations/references_many_as_array.rb +78 -0
  15. data/lib/mongoid/associations/references_one.rb +99 -0
  16. data/lib/mongoid/atomicity.rb +55 -0
  17. data/lib/mongoid/attributes.rb +242 -0
  18. data/lib/mongoid/callbacks.rb +21 -0
  19. data/lib/mongoid/collection.rb +120 -0
  20. data/lib/mongoid/collections.rb +71 -0
  21. data/lib/mongoid/collections/cyclic_iterator.rb +34 -0
  22. data/lib/mongoid/collections/master.rb +29 -0
  23. data/lib/mongoid/collections/operations.rb +41 -0
  24. data/lib/mongoid/collections/slaves.rb +45 -0
  25. data/lib/mongoid/components.rb +34 -0
  26. data/lib/mongoid/config.rb +263 -0
  27. data/lib/mongoid/contexts.rb +24 -0
  28. data/lib/mongoid/contexts/enumerable.rb +156 -0
  29. data/lib/mongoid/contexts/ids.rb +25 -0
  30. data/lib/mongoid/contexts/mongo.rb +285 -0
  31. data/lib/mongoid/contexts/paging.rb +50 -0
  32. data/lib/mongoid/criteria.rb +248 -0
  33. data/lib/mongoid/criterion/complex.rb +21 -0
  34. data/lib/mongoid/criterion/exclusion.rb +65 -0
  35. data/lib/mongoid/criterion/inclusion.rb +110 -0
  36. data/lib/mongoid/criterion/optional.rb +189 -0
  37. data/lib/mongoid/cursor.rb +81 -0
  38. data/lib/mongoid/deprecation.rb +21 -0
  39. data/lib/mongoid/dirty.rb +252 -0
  40. data/lib/mongoid/document.rb +210 -0
  41. data/lib/mongoid/errors.rb +131 -0
  42. data/lib/mongoid/extensions.rb +115 -0
  43. data/lib/mongoid/extensions/array/accessors.rb +17 -0
  44. data/lib/mongoid/extensions/array/assimilation.rb +26 -0
  45. data/lib/mongoid/extensions/array/conversions.rb +23 -0
  46. data/lib/mongoid/extensions/array/parentization.rb +13 -0
  47. data/lib/mongoid/extensions/big_decimal/conversions.rb +19 -0
  48. data/lib/mongoid/extensions/binary/conversions.rb +17 -0
  49. data/lib/mongoid/extensions/boolean/conversions.rb +27 -0
  50. data/lib/mongoid/extensions/date/conversions.rb +24 -0
  51. data/lib/mongoid/extensions/datetime/conversions.rb +12 -0
  52. data/lib/mongoid/extensions/false_class/equality.rb +13 -0
  53. data/lib/mongoid/extensions/float/conversions.rb +20 -0
  54. data/lib/mongoid/extensions/hash/accessors.rb +42 -0
  55. data/lib/mongoid/extensions/hash/assimilation.rb +40 -0
  56. data/lib/mongoid/extensions/hash/conversions.rb +42 -0
  57. data/lib/mongoid/extensions/hash/criteria_helpers.rb +20 -0
  58. data/lib/mongoid/extensions/hash/scoping.rb +12 -0
  59. data/lib/mongoid/extensions/integer/conversions.rb +20 -0
  60. data/lib/mongoid/extensions/nil/assimilation.rb +17 -0
  61. data/lib/mongoid/extensions/object/conversions.rb +21 -0
  62. data/lib/mongoid/extensions/objectid/conversions.rb +15 -0
  63. data/lib/mongoid/extensions/proc/scoping.rb +12 -0
  64. data/lib/mongoid/extensions/set/conversions.rb +20 -0
  65. data/lib/mongoid/extensions/string/conversions.rb +15 -0
  66. data/lib/mongoid/extensions/string/inflections.rb +97 -0
  67. data/lib/mongoid/extensions/symbol/inflections.rb +40 -0
  68. data/lib/mongoid/extensions/time_conversions.rb +35 -0
  69. data/lib/mongoid/extensions/true_class/equality.rb +13 -0
  70. data/lib/mongoid/extras.rb +61 -0
  71. data/lib/mongoid/factory.rb +20 -0
  72. data/lib/mongoid/field.rb +83 -0
  73. data/lib/mongoid/fields.rb +62 -0
  74. data/lib/mongoid/finders.rb +145 -0
  75. data/lib/mongoid/hierarchy.rb +74 -0
  76. data/lib/mongoid/identity.rb +47 -0
  77. data/lib/mongoid/indexes.rb +27 -0
  78. data/lib/mongoid/javascript.rb +21 -0
  79. data/lib/mongoid/javascript/functions.yml +37 -0
  80. data/lib/mongoid/logger.rb +19 -0
  81. data/lib/mongoid/matchers.rb +35 -0
  82. data/lib/mongoid/matchers/all.rb +11 -0
  83. data/lib/mongoid/matchers/default.rb +26 -0
  84. data/lib/mongoid/matchers/exists.rb +13 -0
  85. data/lib/mongoid/matchers/gt.rb +11 -0
  86. data/lib/mongoid/matchers/gte.rb +11 -0
  87. data/lib/mongoid/matchers/in.rb +11 -0
  88. data/lib/mongoid/matchers/lt.rb +11 -0
  89. data/lib/mongoid/matchers/lte.rb +11 -0
  90. data/lib/mongoid/matchers/ne.rb +11 -0
  91. data/lib/mongoid/matchers/nin.rb +11 -0
  92. data/lib/mongoid/matchers/size.rb +11 -0
  93. data/lib/mongoid/memoization.rb +33 -0
  94. data/lib/mongoid/named_scope.rb +37 -0
  95. data/lib/mongoid/paranoia.rb +106 -0
  96. data/lib/mongoid/paths.rb +61 -0
  97. data/lib/mongoid/persistence.rb +216 -0
  98. data/lib/mongoid/persistence/command.rb +39 -0
  99. data/lib/mongoid/persistence/insert.rb +48 -0
  100. data/lib/mongoid/persistence/insert_embedded.rb +44 -0
  101. data/lib/mongoid/persistence/remove.rb +39 -0
  102. data/lib/mongoid/persistence/remove_all.rb +38 -0
  103. data/lib/mongoid/persistence/remove_embedded.rb +50 -0
  104. data/lib/mongoid/persistence/update.rb +71 -0
  105. data/lib/mongoid/railtie.rb +67 -0
  106. data/lib/mongoid/railties/database.rake +60 -0
  107. data/lib/mongoid/scope.rb +75 -0
  108. data/lib/mongoid/state.rb +32 -0
  109. data/lib/mongoid/timestamps.rb +27 -0
  110. data/lib/mongoid/validations.rb +51 -0
  111. data/lib/mongoid/validations/associated.rb +32 -0
  112. data/lib/mongoid/validations/locale/en.yml +5 -0
  113. data/lib/mongoid/validations/uniqueness.rb +56 -0
  114. data/lib/mongoid/version.rb +4 -0
  115. data/lib/mongoid/versioning.rb +26 -0
  116. data/lib/rails/generators/mongoid/config/config_generator.rb +25 -0
  117. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +24 -0
  118. data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
  119. data/lib/rails/generators/mongoid/model/templates/model.rb +15 -0
  120. data/lib/rails/generators/mongoid_generator.rb +61 -0
  121. data/spec/integration/mongoid/association_attributes_spec.rb +71 -0
  122. data/spec/integration/mongoid/associations_spec.rb +768 -0
  123. data/spec/integration/mongoid/attributes_spec.rb +59 -0
  124. data/spec/integration/mongoid/callback_spec.rb +33 -0
  125. data/spec/integration/mongoid/contexts/enumerable_spec.rb +33 -0
  126. data/spec/integration/mongoid/criteria_spec.rb +281 -0
  127. data/spec/integration/mongoid/dirty_spec.rb +85 -0
  128. data/spec/integration/mongoid/document_spec.rb +741 -0
  129. data/spec/integration/mongoid/extensions_spec.rb +22 -0
  130. data/spec/integration/mongoid/finders_spec.rb +119 -0
  131. data/spec/integration/mongoid/inheritance_spec.rb +171 -0
  132. data/spec/integration/mongoid/named_scope_spec.rb +58 -0
  133. data/spec/integration/mongoid/paranoia_spec.rb +44 -0
  134. data/spec/integration/mongoid/persistence/update_spec.rb +46 -0
  135. data/spec/integration/mongoid/persistence_spec.rb +311 -0
  136. data/spec/integration/mongoid/validations/uniqueness_spec.rb +206 -0
  137. data/spec/models/account.rb +5 -0
  138. data/spec/models/address.rb +40 -0
  139. data/spec/models/agent.rb +7 -0
  140. data/spec/models/animal.rb +15 -0
  141. data/spec/models/answer.rb +4 -0
  142. data/spec/models/callbacks.rb +47 -0
  143. data/spec/models/category.rb +13 -0
  144. data/spec/models/comment.rb +10 -0
  145. data/spec/models/country_code.rb +6 -0
  146. data/spec/models/employer.rb +5 -0
  147. data/spec/models/favorite.rb +8 -0
  148. data/spec/models/game.rb +9 -0
  149. data/spec/models/inheritance.rb +72 -0
  150. data/spec/models/location.rb +5 -0
  151. data/spec/models/login.rb +6 -0
  152. data/spec/models/mixed_drink.rb +4 -0
  153. data/spec/models/name.rb +13 -0
  154. data/spec/models/namespacing.rb +11 -0
  155. data/spec/models/paranoid_post.rb +18 -0
  156. data/spec/models/parents.rb +32 -0
  157. data/spec/models/patient.rb +15 -0
  158. data/spec/models/person.rb +106 -0
  159. data/spec/models/pet.rb +7 -0
  160. data/spec/models/pet_owner.rb +6 -0
  161. data/spec/models/phone.rb +7 -0
  162. data/spec/models/post.rb +25 -0
  163. data/spec/models/preference.rb +7 -0
  164. data/spec/models/question.rb +8 -0
  165. data/spec/models/survey.rb +6 -0
  166. data/spec/models/translation.rb +5 -0
  167. data/spec/models/user.rb +6 -0
  168. data/spec/models/user_accout.rb +5 -0
  169. data/spec/models/vet_visit.rb +5 -0
  170. data/spec/models/video.rb +5 -0
  171. data/spec/spec_helper.rb +33 -0
  172. data/spec/unit/mongoid/associations/embedded_in_spec.rb +193 -0
  173. data/spec/unit/mongoid/associations/embeds_many_spec.rb +626 -0
  174. data/spec/unit/mongoid/associations/embeds_one_spec.rb +287 -0
  175. data/spec/unit/mongoid/associations/foreign_key_spec.rb +90 -0
  176. data/spec/unit/mongoid/associations/meta_data_spec.rb +110 -0
  177. data/spec/unit/mongoid/associations/options_spec.rb +215 -0
  178. data/spec/unit/mongoid/associations/referenced_in_spec.rb +145 -0
  179. data/spec/unit/mongoid/associations/references_many_as_array_spec.rb +424 -0
  180. data/spec/unit/mongoid/associations/references_many_spec.rb +502 -0
  181. data/spec/unit/mongoid/associations/references_one_spec.rb +204 -0
  182. data/spec/unit/mongoid/associations_spec.rb +688 -0
  183. data/spec/unit/mongoid/atomicity_spec.rb +164 -0
  184. data/spec/unit/mongoid/attributes_spec.rb +646 -0
  185. data/spec/unit/mongoid/callbacks_spec.rb +85 -0
  186. data/spec/unit/mongoid/collection_spec.rb +187 -0
  187. data/spec/unit/mongoid/collections/cyclic_iterator_spec.rb +75 -0
  188. data/spec/unit/mongoid/collections/master_spec.rb +41 -0
  189. data/spec/unit/mongoid/collections/slaves_spec.rb +81 -0
  190. data/spec/unit/mongoid/collections_spec.rb +98 -0
  191. data/spec/unit/mongoid/config_spec.rb +298 -0
  192. data/spec/unit/mongoid/contexts/enumerable_spec.rb +447 -0
  193. data/spec/unit/mongoid/contexts/mongo_spec.rb +703 -0
  194. data/spec/unit/mongoid/contexts_spec.rb +25 -0
  195. data/spec/unit/mongoid/criteria_spec.rb +873 -0
  196. data/spec/unit/mongoid/criterion/complex_spec.rb +17 -0
  197. data/spec/unit/mongoid/criterion/exclusion_spec.rb +121 -0
  198. data/spec/unit/mongoid/criterion/inclusion_spec.rb +274 -0
  199. data/spec/unit/mongoid/criterion/optional_spec.rb +483 -0
  200. data/spec/unit/mongoid/cursor_spec.rb +80 -0
  201. data/spec/unit/mongoid/deprecation_spec.rb +24 -0
  202. data/spec/unit/mongoid/dirty_spec.rb +430 -0
  203. data/spec/unit/mongoid/document_spec.rb +623 -0
  204. data/spec/unit/mongoid/errors_spec.rb +154 -0
  205. data/spec/unit/mongoid/extensions/array/accessors_spec.rb +50 -0
  206. data/spec/unit/mongoid/extensions/array/assimilation_spec.rb +24 -0
  207. data/spec/unit/mongoid/extensions/array/conversions_spec.rb +52 -0
  208. data/spec/unit/mongoid/extensions/array/parentization_spec.rb +20 -0
  209. data/spec/unit/mongoid/extensions/big_decimal/conversions_spec.rb +36 -0
  210. data/spec/unit/mongoid/extensions/binary/conversions_spec.rb +22 -0
  211. data/spec/unit/mongoid/extensions/boolean/conversions_spec.rb +49 -0
  212. data/spec/unit/mongoid/extensions/date/conversions_spec.rb +145 -0
  213. data/spec/unit/mongoid/extensions/datetime/conversions_spec.rb +14 -0
  214. data/spec/unit/mongoid/extensions/false_class/equality_spec.rb +35 -0
  215. data/spec/unit/mongoid/extensions/float/conversions_spec.rb +61 -0
  216. data/spec/unit/mongoid/extensions/hash/accessors_spec.rb +184 -0
  217. data/spec/unit/mongoid/extensions/hash/assimilation_spec.rb +59 -0
  218. data/spec/unit/mongoid/extensions/hash/conversions_spec.rb +35 -0
  219. data/spec/unit/mongoid/extensions/hash/criteria_helpers_spec.rb +17 -0
  220. data/spec/unit/mongoid/extensions/hash/scoping_spec.rb +14 -0
  221. data/spec/unit/mongoid/extensions/integer/conversions_spec.rb +61 -0
  222. data/spec/unit/mongoid/extensions/nil/assimilation_spec.rb +29 -0
  223. data/spec/unit/mongoid/extensions/object/conversions_spec.rb +44 -0
  224. data/spec/unit/mongoid/extensions/objectid/conversions_spec.rb +22 -0
  225. data/spec/unit/mongoid/extensions/proc/scoping_spec.rb +34 -0
  226. data/spec/unit/mongoid/extensions/set/conversions_spec.rb +21 -0
  227. data/spec/unit/mongoid/extensions/string/conversions_spec.rb +28 -0
  228. data/spec/unit/mongoid/extensions/string/inflections_spec.rb +208 -0
  229. data/spec/unit/mongoid/extensions/symbol/inflections_spec.rb +107 -0
  230. data/spec/unit/mongoid/extensions/time_conversions_spec.rb +186 -0
  231. data/spec/unit/mongoid/extensions/true_class/equality_spec.rb +35 -0
  232. data/spec/unit/mongoid/extras_spec.rb +102 -0
  233. data/spec/unit/mongoid/factory_spec.rb +31 -0
  234. data/spec/unit/mongoid/field_spec.rb +169 -0
  235. data/spec/unit/mongoid/fields_spec.rb +181 -0
  236. data/spec/unit/mongoid/finders_spec.rb +439 -0
  237. data/spec/unit/mongoid/hierarchy_spec.rb +68 -0
  238. data/spec/unit/mongoid/identity_spec.rb +109 -0
  239. data/spec/unit/mongoid/indexes_spec.rb +99 -0
  240. data/spec/unit/mongoid/javascript_spec.rb +48 -0
  241. data/spec/unit/mongoid/logger_spec.rb +38 -0
  242. data/spec/unit/mongoid/matchers/all_spec.rb +27 -0
  243. data/spec/unit/mongoid/matchers/default_spec.rb +27 -0
  244. data/spec/unit/mongoid/matchers/exists_spec.rb +56 -0
  245. data/spec/unit/mongoid/matchers/gt_spec.rb +39 -0
  246. data/spec/unit/mongoid/matchers/gte_spec.rb +49 -0
  247. data/spec/unit/mongoid/matchers/in_spec.rb +27 -0
  248. data/spec/unit/mongoid/matchers/lt_spec.rb +39 -0
  249. data/spec/unit/mongoid/matchers/lte_spec.rb +49 -0
  250. data/spec/unit/mongoid/matchers/ne_spec.rb +27 -0
  251. data/spec/unit/mongoid/matchers/nin_spec.rb +27 -0
  252. data/spec/unit/mongoid/matchers/size_spec.rb +27 -0
  253. data/spec/unit/mongoid/matchers_spec.rb +329 -0
  254. data/spec/unit/mongoid/memoization_spec.rb +75 -0
  255. data/spec/unit/mongoid/named_scope_spec.rb +123 -0
  256. data/spec/unit/mongoid/paranoia_spec.rb +108 -0
  257. data/spec/unit/mongoid/paths_spec.rb +272 -0
  258. data/spec/unit/mongoid/persistence/insert_embedded_spec.rb +154 -0
  259. data/spec/unit/mongoid/persistence/insert_spec.rb +144 -0
  260. data/spec/unit/mongoid/persistence/remove_all_spec.rb +82 -0
  261. data/spec/unit/mongoid/persistence/remove_embedded_spec.rb +152 -0
  262. data/spec/unit/mongoid/persistence/remove_spec.rb +89 -0
  263. data/spec/unit/mongoid/persistence/update_spec.rb +177 -0
  264. data/spec/unit/mongoid/persistence_spec.rb +452 -0
  265. data/spec/unit/mongoid/scope_spec.rb +240 -0
  266. data/spec/unit/mongoid/serialization_spec.rb +43 -0
  267. data/spec/unit/mongoid/state_spec.rb +94 -0
  268. data/spec/unit/mongoid/timestamps_spec.rb +30 -0
  269. data/spec/unit/mongoid/validations/associated_spec.rb +103 -0
  270. data/spec/unit/mongoid/validations/uniqueness_spec.rb +201 -0
  271. data/spec/unit/mongoid/validations_spec.rb +43 -0
  272. data/spec/unit/mongoid/versioning_spec.rb +41 -0
  273. data/spec/unit/mongoid_spec.rb +46 -0
  274. metadata +433 -0
@@ -0,0 +1,74 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Associations #:nodoc:
4
+ # Represents an association that is embedded within another document in the
5
+ # database, either as one or many.
6
+ class EmbeddedIn < Proxy
7
+
8
+ # Creates the new association by setting the internal
9
+ # target as the passed in Document. This should be the
10
+ # parent.
11
+ #
12
+ # All method calls on this object will then be delegated
13
+ # to the internal document itself.
14
+ #
15
+ # Options:
16
+ #
17
+ # target: The parent +Document+
18
+ # options: The association options
19
+ def initialize(target, options)
20
+ @target, @options = target, options
21
+ extends(options)
22
+ end
23
+
24
+ # Returns the parent document. The id param is present for
25
+ # compatibility with rails, however this could be overwritten
26
+ # in the future.
27
+ def find(id)
28
+ @target
29
+ end
30
+
31
+ class << self
32
+ # Creates the new association by setting the internal
33
+ # document as the passed in Document. This should be the
34
+ # parent.
35
+ #
36
+ # Options:
37
+ #
38
+ # document: The parent +Document+
39
+ # options: The association options
40
+ def instantiate(document, options)
41
+ target = document._parent
42
+ target.nil? ? nil : new(target, options)
43
+ end
44
+
45
+ # Returns the macro used to create the association.
46
+ def macro
47
+ :embedded_in
48
+ end
49
+
50
+ # Perform an update of the relationship of the parent and child. This
51
+ # is initialized by setting a parent object as the association on the
52
+ # +Document+. Will properly set an embeds_one or an embeds_many.
53
+ #
54
+ # Returns:
55
+ #
56
+ # A new +EmbeddedIn+ association proxy.
57
+ def update(target, child, options)
58
+ inverse = determine_name(target, options)
59
+ child.parentize(target, inverse)
60
+ child.notify
61
+ target.unmemoize(inverse)
62
+ instantiate(child, options)
63
+ end
64
+
65
+ protected
66
+ def determine_name(target, options)
67
+ inverse = options.inverse_of
68
+ return inverse unless inverse.is_a?(Array)
69
+ inverse.detect { |name| target.respond_to?(name) }
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,280 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Associations #:nodoc:
4
+ # Represents embedding many documents within a parent document, which will
5
+ # be an array as the underlying storage mechanism.
6
+ class EmbedsMany < Proxy
7
+
8
+ attr_accessor :association_name, :klass
9
+
10
+ # Appends the object to the +Array+, setting its parent in
11
+ # the process.
12
+ def <<(*documents)
13
+ documents.flatten.each do |doc|
14
+ doc.parentize(@parent, @association_name)
15
+ @target << doc
16
+ doc._index = @target.size - 1
17
+ doc.notify
18
+ end
19
+ end
20
+
21
+ alias :concat :<<
22
+ alias :push :<<
23
+
24
+ # Builds a new Document and adds it to the association collection. The
25
+ # document created will be of the same class as the others in the
26
+ # association, and the attributes will be passed into the constructor.
27
+ #
28
+ # Returns:
29
+ #
30
+ # The newly created Document.
31
+ def build(attrs = {}, type = nil)
32
+ document = type ? type.instantiate : @klass.instantiate
33
+ document.parentize(@parent, @association_name)
34
+ document.write_attributes(attrs)
35
+ @target << document
36
+ document._index = @target.size - 1
37
+ document
38
+ end
39
+
40
+ # Clears the association, and notifies the parents of the removal.
41
+ def clear
42
+ unless @target.empty?
43
+ document = @target.first
44
+ document._parent.update_child(document, true) if (document._parent)
45
+ @target.clear
46
+ end
47
+ end
48
+
49
+ # Returns a count of the number of documents in the association that have
50
+ # actually been persisted to the database.
51
+ #
52
+ # Use #size if you want the total number of documents.
53
+ #
54
+ # Returns:
55
+ #
56
+ # The total number of persisted embedded docs, as flagged by the
57
+ # #persisted? method.
58
+ def count
59
+ @target.select(&:persisted?).size
60
+ end
61
+
62
+ # Creates a new Document and adds it to the association collection. The
63
+ # document created will be of the same class as the others in the
64
+ # association, and the attributes will be passed into the constructor and
65
+ # the new object will then be saved.
66
+ #
67
+ # Returns:
68
+ #
69
+ # The newly created Document.
70
+ def create(attrs = {}, type = nil)
71
+ build(attrs, type).tap(&:save)
72
+ end
73
+
74
+ # Creates a new Document and adds it to the association collection. The
75
+ # document created will be of the same class as the others in the
76
+ # association, and the attributes will be passed into the constructor and
77
+ # the new object will then be saved. If validation fails an error will
78
+ # get raised.
79
+ #
80
+ # Returns:
81
+ #
82
+ # The newly created Document.
83
+ def create!(attrs = {}, type = nil)
84
+ document = create(attrs, type)
85
+ raise Errors::Validations.new(document) unless document.errors.empty?
86
+ document
87
+ end
88
+
89
+ # Delete all the documents in the association without running callbacks.
90
+ #
91
+ # Example:
92
+ #
93
+ # <tt>addresses.delete_all</tt>
94
+ #
95
+ # Returns:
96
+ #
97
+ # The number of documents deleted.
98
+ def delete_all(conditions = {})
99
+ remove(:delete, conditions)
100
+ end
101
+
102
+ # Delete all the documents in the association and run destroy callbacks.
103
+ #
104
+ # Example:
105
+ #
106
+ # <tt>addresses.destroy_all</tt>
107
+ #
108
+ # Returns:
109
+ #
110
+ # The number of documents destroyed.
111
+ def destroy_all(conditions = {})
112
+ remove(:destroy, conditions)
113
+ end
114
+
115
+ # Finds a document in this association.
116
+ #
117
+ # If :all is passed, returns all the documents
118
+ #
119
+ # If an id is passed, will return the document for that id.
120
+ #
121
+ # Returns:
122
+ #
123
+ # Array or single Document.
124
+ def find(param)
125
+ return @target if param == :all
126
+ return detect { |document| document.id == param }
127
+ end
128
+
129
+ # Creates the new association by finding the attributes in
130
+ # the parent document with its name, and instantiating a
131
+ # new document for each one found. These will then be put in an
132
+ # internal array.
133
+ #
134
+ # This then delegated all methods to the array class since this is
135
+ # essentially a proxy to an array itself.
136
+ #
137
+ # Options:
138
+ #
139
+ # parent: The parent document to the association.
140
+ # options: The association options.
141
+ def initialize(parent, options, target_array = nil)
142
+ @parent, @association_name = parent, options.name
143
+ @klass, @options = options.klass, options
144
+ if target_array
145
+ build_children_from_target_array(target_array)
146
+ else
147
+ build_children_from_attributes(parent.raw_attributes[@association_name])
148
+ end
149
+ extends(options)
150
+ end
151
+
152
+
153
+
154
+ # If the target array does not respond to the supplied method then try to
155
+ # find a named scope or criteria on the class and send the call there.
156
+ #
157
+ # If the method exists on the array, use the default proxy behavior.
158
+ def method_missing(name, *args, &block)
159
+ unless @target.respond_to?(name)
160
+ object = @klass.send(name, *args)
161
+ object.documents = @target
162
+ return object
163
+ end
164
+ super
165
+ end
166
+
167
+ # Used for setting associations via a nested attributes setter from the
168
+ # parent +Document+.
169
+ #
170
+ # Options:
171
+ #
172
+ # attributes: A +Hash+ of integer keys and +Hash+ values.
173
+ #
174
+ # Returns:
175
+ #
176
+ # The newly build target Document.
177
+ def nested_build(attributes, options = {})
178
+ @parent.instance_variable_set(:@building_nested, true)
179
+ deleted_indexes = []
180
+ attributes.each do |index, attrs|
181
+ if document = detect { |document| document._index == index.to_i }
182
+ if options && options[:allow_destroy] && attrs['_destroy']
183
+ deleted_indexes << document._index
184
+ @target.delete(document)
185
+ document.destroy
186
+ else
187
+ document.write_attributes(attrs)
188
+ document._index = index.to_i - deleted_indexes.collect { |i| i < index.to_i }.size
189
+ end
190
+ else
191
+ build(attrs)
192
+ end
193
+ end
194
+ @parent.instance_variable_set(:@building_nested, false)
195
+ self
196
+ end
197
+
198
+ # Paginate the association. Will create a new criteria, set the documents
199
+ # on it and execute in an enumerable context.
200
+ #
201
+ # Options:
202
+ #
203
+ # options: A +Hash+ of pagination options.
204
+ #
205
+ # Returns:
206
+ #
207
+ # A +WillPaginate::Collection+.
208
+ def paginate(options)
209
+ criteria = Mongoid::Criteria.translate(@klass, options)
210
+ criteria.documents = @target
211
+ criteria.paginate(options)
212
+ end
213
+
214
+ protected
215
+ # Initializes each of the attributes in the hash.
216
+ def build_children_from_attributes(attributes)
217
+ @target = []
218
+ if attributes
219
+ attributes.each_with_index do |attrs, index|
220
+ klass = attrs.klass
221
+ child = klass ? klass.instantiate(attrs) : @klass.instantiate(attrs)
222
+ child.parentize(@parent, @association_name)
223
+ child._index = index
224
+ @target << child
225
+ end
226
+ end
227
+ end
228
+
229
+ # Initializes the target array from an existing array of documents.
230
+ def build_children_from_target_array(target_array)
231
+ @target = target_array
232
+ @target.each_with_index do |child, index|
233
+ child._index = index
234
+ end
235
+ end
236
+
237
+ # Removes documents based on a method.
238
+ def remove(method, conditions)
239
+ criteria = @klass.find(conditions || {})
240
+ criteria.documents = @target
241
+ count = criteria.size
242
+ criteria.each do |doc|
243
+ @target.delete(doc); doc.send(method)
244
+ end; count
245
+ end
246
+
247
+ class << self
248
+
249
+ # Preferred method of creating a new +EmbedsMany+ association. It will
250
+ # delegate to new.
251
+ #
252
+ # Options:
253
+ #
254
+ # document: The parent +Document+
255
+ # options: The association options
256
+ def instantiate(document, options, target_array = nil)
257
+ new(document, options, target_array)
258
+ end
259
+
260
+ # Returns the macro used to create the association.
261
+ def macro
262
+ :embeds_many
263
+ end
264
+
265
+ # Perform an update of the relationship of the parent and child. This
266
+ # is initialized by setting the has_many to the supplied +Enumerable+
267
+ # and setting up the parentization.
268
+ def update(children, parent, options)
269
+ parent.raw_attributes.delete(options.name)
270
+ children.assimilate(parent, options)
271
+ if children && children.first.is_a?(Mongoid::Document)
272
+ instantiate(parent, options, children)
273
+ else
274
+ instantiate(parent, options)
275
+ end
276
+ end
277
+ end
278
+ end
279
+ end
280
+ end
@@ -0,0 +1,97 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Associations #:nodoc:
4
+ # Represents an association that is embedded in a parent document as a
5
+ # one-to-one relationship.
6
+ class EmbedsOne < Proxy
7
+
8
+ # Build a new object for the association.
9
+ def build(attrs = {}, type = nil)
10
+ @target = attrs.assimilate(@parent, @options, type); self
11
+ end
12
+
13
+ # Creates the new association by finding the attributes in
14
+ # the parent document with its name, and instantiating a
15
+ # new document for it.
16
+ #
17
+ # All method calls on this object will then be delegated
18
+ # to the internal document itself.
19
+ #
20
+ # Options:
21
+ #
22
+ # document: The parent +Document+
23
+ # attributes: The attributes of the target object.
24
+ # options: The association options.
25
+ #
26
+ # Returns:
27
+ #
28
+ # A new +HashOne+ association proxy.
29
+ def initialize(document, attrs, options, target = nil)
30
+ @parent, @options = document, options
31
+ @target = target ? target : attrs.assimilate(@parent, @options, attrs.klass)
32
+ extends(options)
33
+ end
34
+
35
+ # Used for setting the association via a nested attributes setter on the
36
+ # parent +Document+. Called when using accepts_nested_attributes_for.
37
+ #
38
+ # Options:
39
+ #
40
+ # attributes: The attributes for the new association
41
+ #
42
+ # Returns:
43
+ #
44
+ # A new target document.
45
+ def nested_build(attributes, options = nil)
46
+ unless @target.blank? && options[:update_only]
47
+ @target.write_attributes(attributes)
48
+ end; @target
49
+ end
50
+
51
+ class << self
52
+ # Preferred method of instantiating a new +EmbedsOne+, since nil values
53
+ # will be handled properly.
54
+ #
55
+ # Options:
56
+ #
57
+ # document: The parent +Document+
58
+ # options: The association options.
59
+ #
60
+ # Returns:
61
+ #
62
+ # A new +EmbedsOne+ association proxy.
63
+ def instantiate(document, options, target = nil)
64
+ attributes = document.raw_attributes[options.name]
65
+ return nil if attributes.blank? && target.nil?
66
+ new(document, attributes, options, target)
67
+ end
68
+
69
+ # Returns the macro used to create the association.
70
+ def macro
71
+ :embeds_one
72
+ end
73
+
74
+ # Perform an update of the relationship of the parent and child. This
75
+ # will assimilate the child +Document+ into the parent's object graph.
76
+ #
77
+ # Options:
78
+ #
79
+ # child: The child +Document+ or +Hash+.
80
+ # parent: The parent +Document+ to update.
81
+ # options: The association +Options+
82
+ #
83
+ # Example:
84
+ #
85
+ # <tt>EmbedsOne.update({:first_name => "Hank"}, person, options)</tt>
86
+ #
87
+ # Returns:
88
+ #
89
+ # A new +EmbedsOne+ association proxy.
90
+ def update(child, parent, options)
91
+ child.assimilate(parent, options)
92
+ instantiate(parent, options, child.is_a?(Hash) ? nil : child)
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end