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,164 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Atomicity do
4
+
5
+ describe "#_updates" do
6
+
7
+ context "when the root and embedded documets have changed" do
8
+
9
+ before do
10
+ @person = Person.new(:title => "Grand Poobah")
11
+ @person.instance_variable_set(:@new_record, false)
12
+ @person.title = "Sir"
13
+ end
14
+
15
+ it "returns a hash of field names and new values" do
16
+ @person._updates.should ==
17
+ { "$set" => { "title" => "Sir" } }
18
+ end
19
+
20
+ context "with a new embedded document" do
21
+
22
+ context "when the document is an embeds many" do
23
+
24
+ before do
25
+ @address = Address.new(:street => "Oxford St")
26
+ @person.addresses << @address
27
+ end
28
+
29
+ it "returns a hash of field names and new values" do
30
+ @person._updates.should ==
31
+ {
32
+ "$set" => { "title" => "Sir" },
33
+ "$pushAll" => { "addresses" => [{ "_id" => "oxford-st", "street" => "Oxford St" }]}
34
+ }
35
+ end
36
+ end
37
+
38
+ context "when the document is an embeds one" do
39
+
40
+ before do
41
+ @name = Name.new(:first_name => "Lionel")
42
+ @person.name = @name
43
+ end
44
+
45
+ it "returns a hash of field names and new values" do
46
+ @person._updates.should ==
47
+ {
48
+ "$set" => {
49
+ "title" => "Sir",
50
+ "name" => { "_id" => "lionel", "first_name" => "Lionel" }
51
+ },
52
+ }
53
+ end
54
+ end
55
+ end
56
+
57
+ context "with an updated embedded document" do
58
+
59
+ before do
60
+ @address = Address.new(:street => "Oxford St")
61
+ @person.addresses << @address
62
+ @address.instance_variable_set(:@new_record, false)
63
+ @address.street = "Bond St"
64
+ end
65
+
66
+ it "returns a hash of field names and new values" do
67
+ @person._updates.should ==
68
+ { "$set" => { "title" => "Sir", "addresses.0.street" => "Bond St" } }
69
+ end
70
+
71
+ context "with an multi-level updated embeded document" do
72
+
73
+ before do
74
+ @location = Location.new(:name => "Home")
75
+ @location.instance_variable_set(:@new_record, false)
76
+ @address.locations << @location
77
+ @location.name = "Work"
78
+ end
79
+
80
+ it "returns the proper hash with locations" do
81
+ @person._updates.should ==
82
+ { "$set" => {
83
+ "title" => "Sir",
84
+ "addresses.0.street" => "Bond St",
85
+ "addresses.0.locations.0.name" => "Work" }
86
+ }
87
+ end
88
+ end
89
+
90
+ context "with an multi-level new bottom embedded document" do
91
+
92
+ before do
93
+ @location = Location.new(:name => "Home")
94
+ @address.locations << @location
95
+ @location.name = "Work"
96
+ end
97
+
98
+ it "returns the proper hash with locations" do
99
+ @person._updates.should ==
100
+ {
101
+ "$set" => {
102
+ "title" => "Sir",
103
+ "addresses.0.street" => "Bond St"
104
+ },
105
+ "$pushAll" => {
106
+ "addresses.0.locations" => [{ "_id" => @location.id, "name" => "Work" }]
107
+ }
108
+ }
109
+ end
110
+ end
111
+
112
+ context "with multi-level new documents" do
113
+
114
+ before do
115
+ @location = Location.new(:name => "Home")
116
+ @new_address = Address.new(:street => "Another")
117
+ @new_address.locations << @location
118
+ @person.addresses << @new_address
119
+ end
120
+
121
+ it "returns the proper hash with locations" do
122
+ @address.stubs(:_sets).returns({})
123
+ @person._updates.should ==
124
+ {
125
+ "$set" => {
126
+ "title" => "Sir",
127
+ },
128
+ "$pushAll" => {
129
+ "addresses" => [{
130
+ "_id" => @new_address.id,
131
+ "street" => "Another",
132
+ "locations" => [
133
+ "_id" => @location.id,
134
+ "name" => "Home"
135
+ ]
136
+ }]
137
+ }
138
+ }
139
+ end
140
+
141
+ it "returns the proper hash with locations and queue" do
142
+ @person._updates.should ==
143
+ {
144
+ "$set" => {
145
+ "title" => "Sir",
146
+ "addresses.0.street" => "Bond St"
147
+ },
148
+ :other => {
149
+ "addresses" => [{
150
+ "_id" => @new_address.id,
151
+ "street" => "Another",
152
+ "locations" => [
153
+ "_id" => @location.id,
154
+ "name" => "Home"
155
+ ]
156
+ }]
157
+ }
158
+ }
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,646 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Attributes do
4
+
5
+ describe ".accepts_nested_attributes_for" do
6
+
7
+ before do
8
+ @person = Person.new
9
+ end
10
+
11
+ it "adds a setter for the association attributes" do
12
+ @person.should respond_to(:addresses_attributes=)
13
+ end
14
+
15
+ describe "#association_attributes=" do
16
+
17
+ context "on a embeds many association" do
18
+
19
+ context "when a reject block supplied" do
20
+
21
+ before do
22
+ @attributes = {
23
+ "0" => { "city" => "San Francisco" }
24
+ }
25
+ @person.addresses_attributes = @attributes
26
+ end
27
+
28
+ it "removes the attributes that match" do
29
+ @person.addresses.should be_empty
30
+ end
31
+
32
+ end
33
+
34
+ context "when association is empty" do
35
+
36
+ before do
37
+ @attributes = {
38
+ "0" => { "street" => "Folsom", "city" => "San Francisco" }
39
+ }
40
+ @person.addresses_attributes = @attributes
41
+ end
42
+
43
+ it "adds a new document to the association" do
44
+ address = @person.addresses.first
45
+ address.street.should == "Folsom"
46
+ address.city.should == "San Francisco"
47
+ end
48
+
49
+ end
50
+
51
+ context "when association is not empty" do
52
+
53
+ before do
54
+ @person = Person.new
55
+ @person.addresses.build(:street => "Broadway", :city => "New York")
56
+ @attributes = {
57
+ "0" => { "street" => "Folsom", "city" => "San Francisco" }
58
+ }
59
+ @person.addresses_attributes = @attributes
60
+ end
61
+
62
+ it "updates the existing attributes on the association" do
63
+ @person.addresses.size.should == 1
64
+ end
65
+
66
+ end
67
+
68
+ context "when :allow_destroy is enabled" do
69
+ before do
70
+ @person = Person.new(:title => "Sir", :ssn => "555-66-9999")
71
+ @person.favorites.build(:title => "Ice Cream")
72
+ @person.favorites.build(:title => "Jello")
73
+ @person.favorites.build(:title => "Ducce de Lecce")
74
+ @attributes = {
75
+ "0" => { "_destroy" => "true" },
76
+ "1" => { "_destroy" => "true" }
77
+ }
78
+ @person.favorites_attributes = @attributes
79
+ end
80
+
81
+ it "removes the items that have _destroy => true set" do
82
+ @person.favorites.class.should == Array
83
+ @person.favorites.size.should == 1
84
+ @person.favorites.first.title.should == "Ducce de Lecce"
85
+ end
86
+ end
87
+
88
+ context "when :limit is set to 5" do
89
+ before do
90
+ @person = Person.new
91
+ end
92
+
93
+ it "allows adding 5 favorites" do
94
+ @attributes = {
95
+ "0" => { "title" => "Ice Cream" },
96
+ "1" => { "title" => "Jello" },
97
+ "2" => { "title" => "Sorbet" },
98
+ "3" => { "title" => "Cake" },
99
+ "4" => { "title" => "Tim Tams" }
100
+ }
101
+ @person.favorites_attributes = @attributes
102
+ @person.favorites.size.should == 5
103
+ end
104
+
105
+ it "it raises exception when adding more than 5 favorites" do
106
+ @attributes = {
107
+ "0" => { "title" => "Ice Cream" },
108
+ "1" => { "title" => "Jello" },
109
+ "2" => { "title" => "Sorbet" },
110
+ "3" => { "title" => "Cake" },
111
+ "4" => { "title" => "Tim Tams" },
112
+ "5" => { "title" => "Milo" }
113
+ }
114
+ lambda { @person.favorites_attributes = @attributes }.should
115
+ raise_error(Mongoid::Errors::TooManyNestedAttributeRecords)
116
+ end
117
+ end
118
+
119
+ end
120
+
121
+ context "on a has one association" do
122
+
123
+ before do
124
+ @person = Person.new
125
+ end
126
+
127
+ it "can be added if :update_only is false" do
128
+ @person.pet_attributes = { "name" => "Darwin" }
129
+ @person.pet.name.should == "Darwin"
130
+ end
131
+
132
+ it "can be updated if :update_only is false" do
133
+ @person.pet_attributes = { "name" => "Darwin" }
134
+ @person.pet_attributes = { "name" => "Zulu" }
135
+ @person.pet.name.should == "Zulu"
136
+ end
137
+
138
+ it "can not be added if :update_only is true" do
139
+ @person.name_attributes = { "first_name" => "Fernando", "last_name" => "Torres" }
140
+ @person.name.should be_blank
141
+ end
142
+
143
+ it "can be updated if :update_only is true" do
144
+ @person = Person.new(:name => { "first_name" => "Marco", "last_name" => "Polo" })
145
+ @person.name_attributes = { "first_name" => "Fernando", "last_name" => "Torres" }
146
+ @person.name.first_name.should == "Fernando"
147
+ @person.name.last_name.should == "Torres"
148
+ end
149
+ end
150
+ end
151
+ end
152
+
153
+ describe ".attr_protected" do
154
+
155
+ context "when the field is not _id" do
156
+
157
+ before do
158
+ @person = Person.new(:security_code => "ABBA")
159
+ end
160
+
161
+ it "prevents setting via mass assignment" do
162
+ @person.security_code.should be_nil
163
+ end
164
+ end
165
+
166
+ context "when the field is _id" do
167
+
168
+ before do
169
+ @game = Game.new(:_id => "ABBA")
170
+ end
171
+
172
+ it "prevents setting via mass assignment" do
173
+ @game._id.should_not == "ABBA"
174
+ end
175
+ end
176
+
177
+ context "when using instantiate" do
178
+
179
+ before do
180
+ @person = Person.instantiate("_id" => "1", "security_code" => "ABBA")
181
+ end
182
+
183
+ it "ignores any protected attribute" do
184
+ @person.security_code.should == "ABBA"
185
+ end
186
+ end
187
+ end
188
+
189
+ describe "#_id" do
190
+
191
+ before do
192
+ @person = Person.new
193
+ end
194
+
195
+ it "delegates to #id" do
196
+ @person._id.should == @person.id
197
+ end
198
+
199
+ end
200
+
201
+ describe "#_id=" do
202
+
203
+ before do
204
+ @person = Person.new
205
+ end
206
+
207
+ it "delegates to #id=" do
208
+ @id = BSON::ObjectID.new.to_s
209
+ @person._id = @id
210
+ @person.id.should == @id
211
+ end
212
+
213
+ end
214
+
215
+ describe "#method_missing" do
216
+
217
+ before do
218
+ Mongoid.configure.allow_dynamic_fields = true
219
+ @attributes = {
220
+ :testing => "Testing"
221
+ }
222
+ @person = Person.new(@attributes)
223
+ end
224
+
225
+ context "when an attribute exists" do
226
+
227
+ it "allows the getter" do
228
+ @person.testing.should == "Testing"
229
+ end
230
+
231
+ it "allows the setter" do
232
+ @person.testing = "Test"
233
+ @person.testing.should == "Test"
234
+ end
235
+
236
+ end
237
+
238
+ end
239
+
240
+ describe "#process" do
241
+
242
+ context "when passing non accessible fields" do
243
+
244
+ before do
245
+ @person = Person.new(:owner_id => 6)
246
+ end
247
+
248
+ it "does not set the value" do
249
+ @person.owner_id.should be_nil
250
+ end
251
+ end
252
+
253
+ context "when attributes dont have fields defined" do
254
+
255
+ before do
256
+ @attributes = {
257
+ :nofieldstring => "Testing",
258
+ :nofieldint => 5,
259
+ :employer => Employer.new
260
+ }
261
+ end
262
+
263
+ context "when allowing dynamic fields" do
264
+
265
+ before do
266
+ Mongoid.configure.allow_dynamic_fields = true
267
+ @person = Person.new(@attributes)
268
+ end
269
+
270
+ context "when attribute is a string" do
271
+
272
+ it "adds the string to the attributes" do
273
+ @person.attributes[:nofieldstring].should == "Testing"
274
+ end
275
+
276
+ end
277
+
278
+ context "when attribute is not a string" do
279
+
280
+ it "adds a cast value to the attributes" do
281
+ @person.attributes[:nofieldint].should == 5
282
+ end
283
+
284
+ end
285
+
286
+ end
287
+
288
+ context "when not allowing dynamic fields" do
289
+
290
+ before do
291
+ Mongoid.configure.allow_dynamic_fields = false
292
+ Person.fields.delete(:nofieldstring)
293
+ @attributes = {
294
+ :nofieldstring => "Testing"
295
+ }
296
+ end
297
+
298
+ after do
299
+ Mongoid.configure.allow_dynamic_fields = true
300
+ end
301
+
302
+ it "raises an error" do
303
+ lambda { Person.new(@attributes) }.should raise_error
304
+ end
305
+
306
+ end
307
+
308
+ end
309
+
310
+ context "when supplied hash has values" do
311
+
312
+ before do
313
+ @attributes = {
314
+ :_id => "1",
315
+ :title => "value",
316
+ :age => "30",
317
+ :terms => "true",
318
+ :score => "",
319
+ :name => {
320
+ :_id => "2", :first_name => "Test", :last_name => "User"
321
+ },
322
+ :addresses => [
323
+ { :_id => "3", :street => "First Street" },
324
+ { :_id => "4", :street => "Second Street" }
325
+ ]
326
+ }
327
+ end
328
+
329
+ it "returns properly cast attributes" do
330
+ attrs = Person.new(@attributes).attributes
331
+ attrs[:age].should == 30
332
+ attrs[:terms].should == true
333
+ attrs[:_id].should == "1"
334
+ attrs[:score].should be_nil
335
+ end
336
+
337
+ end
338
+
339
+ context "when associations provided in the attributes" do
340
+
341
+ context "when association is a has_one" do
342
+
343
+ before do
344
+ @name = Name.new(:first_name => "Testy")
345
+ @attributes = {
346
+ :name => @name
347
+ }
348
+ @person = Person.new(@attributes)
349
+ end
350
+
351
+ it "sets the associations" do
352
+ @person.name.should == @name
353
+ end
354
+
355
+ end
356
+
357
+ context "when association is a references_one" do
358
+
359
+ before do
360
+ @game = Game.new(:score => 100)
361
+ @attributes = {
362
+ :game => @game
363
+ }
364
+ @person = Person.new(@attributes)
365
+ end
366
+
367
+ it "sets the associations" do
368
+ @person.game.should == @game
369
+ @game.person.should == @person
370
+ end
371
+
372
+ end
373
+
374
+ context "when association is a embedded_in" do
375
+
376
+ before do
377
+ @person = Person.new
378
+ @name = Name.new(:first_name => "Tyler", :person => @person)
379
+ end
380
+
381
+ it "sets the association" do
382
+ @name.person.should == @person
383
+ end
384
+
385
+ end
386
+
387
+ end
388
+
389
+ context "when non-associations provided in the attributes" do
390
+
391
+ before do
392
+ @employer = Employer.new
393
+ @attributes = { :employer_id => @employer.id, :title => "Sir" }
394
+ @person = Person.new(@attributes)
395
+ end
396
+
397
+ it "calls the setter for the association" do
398
+ @person.employer_id.should == "1"
399
+ end
400
+
401
+ end
402
+
403
+ context "when an empty array is provided in the attributes" do
404
+
405
+ before do
406
+ @attributes = {
407
+ :aliases => []
408
+ }
409
+ @person = Person.new(@attributes)
410
+ end
411
+
412
+ it "sets the empty array" do
413
+ @person.aliases.should == []
414
+ end
415
+
416
+ end
417
+
418
+ context "when an empty hash is provided in the attributes" do
419
+
420
+ before do
421
+ @attributes = {
422
+ :map => {}
423
+ }
424
+ @person = Person.new(@attributes)
425
+ end
426
+
427
+ it "sets the empty hash" do
428
+ @person.map.should == {}
429
+ end
430
+
431
+ end
432
+
433
+ end
434
+
435
+ context "updating when attributes already exist" do
436
+
437
+ before do
438
+ @person = Person.new(:title => "Sir")
439
+ @attributes = { :dob => "2000-01-01" }
440
+ end
441
+
442
+ it "only overwrites supplied attributes" do
443
+ @person.process(@attributes)
444
+ @person.title.should == "Sir"
445
+ end
446
+
447
+ end
448
+
449
+ describe "#read_attribute" do
450
+
451
+ context "when attribute does not exist" do
452
+
453
+ before do
454
+ @person = Person.new
455
+ end
456
+
457
+ it "returns the default value" do
458
+ @person.age.should == 100
459
+ @person.pets.should == false
460
+ end
461
+
462
+ end
463
+
464
+ context "when attribute is not accessible" do
465
+
466
+ before do
467
+ @person = Person.new
468
+ @person.owner_id = 5
469
+ end
470
+
471
+ it "returns the value" do
472
+ @person.read_attribute(:owner_id).should == 5
473
+ end
474
+ end
475
+
476
+ end
477
+
478
+ describe "#attribute_present?" do
479
+ context "when attribute does not exist" do
480
+ before do
481
+ @person = Person.new
482
+ end
483
+
484
+ it "returns false" do
485
+ @person.attribute_present?(:owner_id).should be_false
486
+ end
487
+ end
488
+
489
+ context "when attribute does exist" do
490
+ before do
491
+ @person = Person.new
492
+ @person.owner_id = 5
493
+ end
494
+
495
+ it "returns true" do
496
+ @person.attribute_present?(:owner_id).should be_true
497
+ end
498
+ end
499
+ end
500
+
501
+ describe "#remove_attribute" do
502
+
503
+ context "when the attribute exists" do
504
+
505
+ it "removes the attribute" do
506
+ person = Person.new(:title => "Sir")
507
+ person.remove_attribute(:title)
508
+ person.title.should be_nil
509
+ end
510
+
511
+ end
512
+
513
+ context "when the attribute does not exist" do
514
+
515
+ it "does nothing" do
516
+ person = Person.new
517
+ person.remove_attribute(:title)
518
+ person.title.should be_nil
519
+ end
520
+
521
+ end
522
+
523
+ end
524
+
525
+ describe "#write_attribute" do
526
+
527
+ context "when attribute does not exist" do
528
+
529
+ before do
530
+ @person = Person.new
531
+ end
532
+
533
+ it "returns the default value" do
534
+ @person.age.should == 100
535
+ end
536
+
537
+ end
538
+
539
+ context "when setting the attribute to nil" do
540
+
541
+ before do
542
+ @person = Person.new(:age => nil)
543
+ end
544
+
545
+ it "does not use the default value" do
546
+ @person.age.should be_nil
547
+ end
548
+ end
549
+
550
+ context "when field has a default value" do
551
+
552
+ before do
553
+ @person = Person.new
554
+ end
555
+
556
+ it "should allow overwriting of the default value" do
557
+ @person.terms = true
558
+ @person.terms.should be_true
559
+ end
560
+
561
+ end
562
+
563
+ end
564
+
565
+ [:attributes=, :write_attributes].each do |method|
566
+ describe "##{method}" do
567
+
568
+ context "typecasting" do
569
+
570
+ before do
571
+ @person = Person.new
572
+ @attributes = { :age => "50" }
573
+ end
574
+
575
+ it "properly casts values" do
576
+ @person.send(method, @attributes)
577
+ @person.age.should == 50
578
+ end
579
+
580
+ it "allows passing of nil" do
581
+ @person.send(method, nil)
582
+ @person.age.should == 100
583
+ end
584
+
585
+ end
586
+
587
+ context "on a parent document" do
588
+
589
+ context "when the parent has a has many through a has one" do
590
+
591
+ before do
592
+ @owner = PetOwner.new(:title => "Mr")
593
+ @pet = Pet.new(:name => "Fido")
594
+ @owner.pet = @pet
595
+ @vet_visit = VetVisit.new(:date => Date.today)
596
+ @pet.vet_visits = [@vet_visit]
597
+ end
598
+
599
+ it "does not overwrite child attributes if not in the hash" do
600
+ @owner.send(method, { :pet => { :name => "Bingo" } })
601
+ @owner.pet.name.should == "Bingo"
602
+ @owner.pet.vet_visits.size.should == 1
603
+ end
604
+ end
605
+ end
606
+
607
+ context "on a child document" do
608
+
609
+ context "when child is part of a has one" do
610
+
611
+ before do
612
+ @person = Person.new(:title => "Sir", :age => 30)
613
+ @name = Name.new(:first_name => "Test", :last_name => "User")
614
+ @person.name = @name
615
+ end
616
+
617
+ it "sets the child attributes on the parent" do
618
+ @name.send(method, :first_name => "Test2", :last_name => "User2")
619
+ @person.attributes[:name].should ==
620
+ { "_id" => "test-user", "first_name" => "Test2", "last_name" => "User2" }
621
+ end
622
+
623
+ end
624
+
625
+ context "when child is part of a has many" do
626
+
627
+ before do
628
+ @person = Person.new(:title => "Sir")
629
+ @address = Address.new(:street => "Test")
630
+ @person.addresses << @address
631
+ end
632
+
633
+ it "updates the child attributes on the parent" do
634
+ @address.send(method, "street" => "Test2")
635
+ @person.attributes[:addresses].should ==
636
+ [ { "_id" => "test", "street" => "Test2" } ]
637
+ end
638
+
639
+ end
640
+
641
+ end
642
+ end
643
+
644
+ end
645
+
646
+ end