mongoid-multi-db 3.0.0

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 (276) hide show
  1. data/CHANGELOG.md +615 -0
  2. data/LICENSE +20 -0
  3. data/README.md +62 -0
  4. data/Rakefile +49 -0
  5. data/lib/config/locales/bg.yml +54 -0
  6. data/lib/config/locales/de.yml +54 -0
  7. data/lib/config/locales/en-GB.yml +55 -0
  8. data/lib/config/locales/en.yml +55 -0
  9. data/lib/config/locales/es.yml +52 -0
  10. data/lib/config/locales/fr.yml +55 -0
  11. data/lib/config/locales/hi.yml +46 -0
  12. data/lib/config/locales/hu.yml +57 -0
  13. data/lib/config/locales/id.yml +55 -0
  14. data/lib/config/locales/it.yml +52 -0
  15. data/lib/config/locales/ja.yml +50 -0
  16. data/lib/config/locales/kr.yml +47 -0
  17. data/lib/config/locales/nl.yml +52 -0
  18. data/lib/config/locales/pl.yml +52 -0
  19. data/lib/config/locales/pt-BR.yml +53 -0
  20. data/lib/config/locales/pt.yml +53 -0
  21. data/lib/config/locales/ro.yml +59 -0
  22. data/lib/config/locales/ru.yml +54 -0
  23. data/lib/config/locales/sv.yml +53 -0
  24. data/lib/config/locales/vi.yml +55 -0
  25. data/lib/config/locales/zh-CN.yml +46 -0
  26. data/lib/mongoid.rb +148 -0
  27. data/lib/mongoid/atomic.rb +230 -0
  28. data/lib/mongoid/atomic/modifiers.rb +243 -0
  29. data/lib/mongoid/atomic/paths.rb +3 -0
  30. data/lib/mongoid/atomic/paths/embedded.rb +43 -0
  31. data/lib/mongoid/atomic/paths/embedded/many.rb +44 -0
  32. data/lib/mongoid/atomic/paths/embedded/one.rb +43 -0
  33. data/lib/mongoid/atomic/paths/root.rb +40 -0
  34. data/lib/mongoid/attributes.rb +234 -0
  35. data/lib/mongoid/attributes/processing.rb +146 -0
  36. data/lib/mongoid/callbacks.rb +135 -0
  37. data/lib/mongoid/collection.rb +153 -0
  38. data/lib/mongoid/collection_proxy.rb +59 -0
  39. data/lib/mongoid/collections.rb +120 -0
  40. data/lib/mongoid/collections/master.rb +45 -0
  41. data/lib/mongoid/collections/operations.rb +44 -0
  42. data/lib/mongoid/collections/retry.rb +46 -0
  43. data/lib/mongoid/components.rb +96 -0
  44. data/lib/mongoid/config.rb +347 -0
  45. data/lib/mongoid/config/database.rb +186 -0
  46. data/lib/mongoid/config/replset_database.rb +82 -0
  47. data/lib/mongoid/connection_proxy.rb +30 -0
  48. data/lib/mongoid/contexts.rb +25 -0
  49. data/lib/mongoid/contexts/enumerable.rb +288 -0
  50. data/lib/mongoid/contexts/enumerable/sort.rb +43 -0
  51. data/lib/mongoid/contexts/mongo.rb +409 -0
  52. data/lib/mongoid/copyable.rb +48 -0
  53. data/lib/mongoid/criteria.rb +418 -0
  54. data/lib/mongoid/criterion/builder.rb +34 -0
  55. data/lib/mongoid/criterion/complex.rb +84 -0
  56. data/lib/mongoid/criterion/creational.rb +34 -0
  57. data/lib/mongoid/criterion/exclusion.rb +108 -0
  58. data/lib/mongoid/criterion/inclusion.rb +305 -0
  59. data/lib/mongoid/criterion/inspection.rb +22 -0
  60. data/lib/mongoid/criterion/optional.rb +232 -0
  61. data/lib/mongoid/criterion/selector.rb +153 -0
  62. data/lib/mongoid/cursor.rb +86 -0
  63. data/lib/mongoid/database_proxy.rb +97 -0
  64. data/lib/mongoid/default_scope.rb +36 -0
  65. data/lib/mongoid/dirty.rb +110 -0
  66. data/lib/mongoid/document.rb +280 -0
  67. data/lib/mongoid/errors.rb +17 -0
  68. data/lib/mongoid/errors/callback.rb +26 -0
  69. data/lib/mongoid/errors/document_not_found.rb +28 -0
  70. data/lib/mongoid/errors/eager_load.rb +25 -0
  71. data/lib/mongoid/errors/invalid_collection.rb +18 -0
  72. data/lib/mongoid/errors/invalid_database.rb +19 -0
  73. data/lib/mongoid/errors/invalid_field.rb +18 -0
  74. data/lib/mongoid/errors/invalid_find.rb +19 -0
  75. data/lib/mongoid/errors/invalid_options.rb +28 -0
  76. data/lib/mongoid/errors/invalid_time.rb +25 -0
  77. data/lib/mongoid/errors/invalid_type.rb +25 -0
  78. data/lib/mongoid/errors/mixed_relations.rb +37 -0
  79. data/lib/mongoid/errors/mongoid_error.rb +26 -0
  80. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +20 -0
  81. data/lib/mongoid/errors/unsaved_document.rb +23 -0
  82. data/lib/mongoid/errors/unsupported_version.rb +20 -0
  83. data/lib/mongoid/errors/validations.rb +23 -0
  84. data/lib/mongoid/extensions.rb +82 -0
  85. data/lib/mongoid/extensions/array/deletion.rb +29 -0
  86. data/lib/mongoid/extensions/false_class/equality.rb +26 -0
  87. data/lib/mongoid/extensions/hash/criteria_helpers.rb +45 -0
  88. data/lib/mongoid/extensions/hash/scoping.rb +25 -0
  89. data/lib/mongoid/extensions/integer/checks.rb +23 -0
  90. data/lib/mongoid/extensions/nil/collectionization.rb +23 -0
  91. data/lib/mongoid/extensions/object/checks.rb +29 -0
  92. data/lib/mongoid/extensions/object/reflections.rb +48 -0
  93. data/lib/mongoid/extensions/object/substitutable.rb +15 -0
  94. data/lib/mongoid/extensions/object/yoda.rb +44 -0
  95. data/lib/mongoid/extensions/object_id/conversions.rb +60 -0
  96. data/lib/mongoid/extensions/proc/scoping.rb +25 -0
  97. data/lib/mongoid/extensions/string/checks.rb +36 -0
  98. data/lib/mongoid/extensions/string/conversions.rb +22 -0
  99. data/lib/mongoid/extensions/string/inflections.rb +118 -0
  100. data/lib/mongoid/extensions/symbol/checks.rb +23 -0
  101. data/lib/mongoid/extensions/symbol/inflections.rb +66 -0
  102. data/lib/mongoid/extensions/true_class/equality.rb +26 -0
  103. data/lib/mongoid/extras.rb +31 -0
  104. data/lib/mongoid/factory.rb +46 -0
  105. data/lib/mongoid/fields.rb +332 -0
  106. data/lib/mongoid/fields/mappings.rb +41 -0
  107. data/lib/mongoid/fields/serializable.rb +201 -0
  108. data/lib/mongoid/fields/serializable/array.rb +49 -0
  109. data/lib/mongoid/fields/serializable/big_decimal.rb +42 -0
  110. data/lib/mongoid/fields/serializable/bignum.rb +10 -0
  111. data/lib/mongoid/fields/serializable/binary.rb +11 -0
  112. data/lib/mongoid/fields/serializable/boolean.rb +43 -0
  113. data/lib/mongoid/fields/serializable/date.rb +51 -0
  114. data/lib/mongoid/fields/serializable/date_time.rb +28 -0
  115. data/lib/mongoid/fields/serializable/fixnum.rb +10 -0
  116. data/lib/mongoid/fields/serializable/float.rb +32 -0
  117. data/lib/mongoid/fields/serializable/foreign_keys/array.rb +42 -0
  118. data/lib/mongoid/fields/serializable/foreign_keys/object.rb +47 -0
  119. data/lib/mongoid/fields/serializable/hash.rb +11 -0
  120. data/lib/mongoid/fields/serializable/integer.rb +44 -0
  121. data/lib/mongoid/fields/serializable/localized.rb +41 -0
  122. data/lib/mongoid/fields/serializable/nil_class.rb +38 -0
  123. data/lib/mongoid/fields/serializable/object.rb +11 -0
  124. data/lib/mongoid/fields/serializable/object_id.rb +31 -0
  125. data/lib/mongoid/fields/serializable/range.rb +42 -0
  126. data/lib/mongoid/fields/serializable/set.rb +42 -0
  127. data/lib/mongoid/fields/serializable/string.rb +27 -0
  128. data/lib/mongoid/fields/serializable/symbol.rb +27 -0
  129. data/lib/mongoid/fields/serializable/time.rb +23 -0
  130. data/lib/mongoid/fields/serializable/time_with_zone.rb +23 -0
  131. data/lib/mongoid/fields/serializable/timekeeping.rb +106 -0
  132. data/lib/mongoid/finders.rb +152 -0
  133. data/lib/mongoid/hierarchy.rb +120 -0
  134. data/lib/mongoid/identity.rb +92 -0
  135. data/lib/mongoid/identity_map.rb +119 -0
  136. data/lib/mongoid/indexes.rb +54 -0
  137. data/lib/mongoid/inspection.rb +54 -0
  138. data/lib/mongoid/javascript.rb +20 -0
  139. data/lib/mongoid/javascript/functions.yml +63 -0
  140. data/lib/mongoid/json.rb +16 -0
  141. data/lib/mongoid/keys.rb +144 -0
  142. data/lib/mongoid/logger.rb +39 -0
  143. data/lib/mongoid/matchers.rb +32 -0
  144. data/lib/mongoid/matchers/all.rb +21 -0
  145. data/lib/mongoid/matchers/and.rb +30 -0
  146. data/lib/mongoid/matchers/default.rb +70 -0
  147. data/lib/mongoid/matchers/exists.rb +23 -0
  148. data/lib/mongoid/matchers/gt.rb +21 -0
  149. data/lib/mongoid/matchers/gte.rb +21 -0
  150. data/lib/mongoid/matchers/in.rb +21 -0
  151. data/lib/mongoid/matchers/lt.rb +21 -0
  152. data/lib/mongoid/matchers/lte.rb +21 -0
  153. data/lib/mongoid/matchers/ne.rb +21 -0
  154. data/lib/mongoid/matchers/nin.rb +21 -0
  155. data/lib/mongoid/matchers/or.rb +33 -0
  156. data/lib/mongoid/matchers/size.rb +21 -0
  157. data/lib/mongoid/matchers/strategies.rb +93 -0
  158. data/lib/mongoid/multi_database.rb +31 -0
  159. data/lib/mongoid/multi_parameter_attributes.rb +106 -0
  160. data/lib/mongoid/named_scope.rb +146 -0
  161. data/lib/mongoid/nested_attributes.rb +54 -0
  162. data/lib/mongoid/observer.rb +170 -0
  163. data/lib/mongoid/paranoia.rb +158 -0
  164. data/lib/mongoid/persistence.rb +264 -0
  165. data/lib/mongoid/persistence/atomic.rb +223 -0
  166. data/lib/mongoid/persistence/atomic/add_to_set.rb +35 -0
  167. data/lib/mongoid/persistence/atomic/bit.rb +37 -0
  168. data/lib/mongoid/persistence/atomic/inc.rb +31 -0
  169. data/lib/mongoid/persistence/atomic/operation.rb +85 -0
  170. data/lib/mongoid/persistence/atomic/pop.rb +34 -0
  171. data/lib/mongoid/persistence/atomic/pull.rb +34 -0
  172. data/lib/mongoid/persistence/atomic/pull_all.rb +34 -0
  173. data/lib/mongoid/persistence/atomic/push.rb +31 -0
  174. data/lib/mongoid/persistence/atomic/push_all.rb +31 -0
  175. data/lib/mongoid/persistence/atomic/rename.rb +31 -0
  176. data/lib/mongoid/persistence/atomic/sets.rb +30 -0
  177. data/lib/mongoid/persistence/atomic/unset.rb +28 -0
  178. data/lib/mongoid/persistence/deletion.rb +32 -0
  179. data/lib/mongoid/persistence/insertion.rb +41 -0
  180. data/lib/mongoid/persistence/modification.rb +37 -0
  181. data/lib/mongoid/persistence/operations.rb +211 -0
  182. data/lib/mongoid/persistence/operations/embedded/insert.rb +42 -0
  183. data/lib/mongoid/persistence/operations/embedded/remove.rb +40 -0
  184. data/lib/mongoid/persistence/operations/insert.rb +34 -0
  185. data/lib/mongoid/persistence/operations/remove.rb +33 -0
  186. data/lib/mongoid/persistence/operations/update.rb +64 -0
  187. data/lib/mongoid/railtie.rb +126 -0
  188. data/lib/mongoid/railties/database.rake +182 -0
  189. data/lib/mongoid/railties/document.rb +12 -0
  190. data/lib/mongoid/relations.rb +144 -0
  191. data/lib/mongoid/relations/accessors.rb +138 -0
  192. data/lib/mongoid/relations/auto_save.rb +38 -0
  193. data/lib/mongoid/relations/binding.rb +26 -0
  194. data/lib/mongoid/relations/bindings.rb +9 -0
  195. data/lib/mongoid/relations/bindings/embedded/in.rb +69 -0
  196. data/lib/mongoid/relations/bindings/embedded/many.rb +93 -0
  197. data/lib/mongoid/relations/bindings/embedded/one.rb +61 -0
  198. data/lib/mongoid/relations/bindings/referenced/in.rb +76 -0
  199. data/lib/mongoid/relations/bindings/referenced/many.rb +54 -0
  200. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +51 -0
  201. data/lib/mongoid/relations/bindings/referenced/one.rb +58 -0
  202. data/lib/mongoid/relations/builder.rb +57 -0
  203. data/lib/mongoid/relations/builders.rb +83 -0
  204. data/lib/mongoid/relations/builders/embedded/in.rb +29 -0
  205. data/lib/mongoid/relations/builders/embedded/many.rb +40 -0
  206. data/lib/mongoid/relations/builders/embedded/one.rb +30 -0
  207. data/lib/mongoid/relations/builders/nested_attributes/many.rb +110 -0
  208. data/lib/mongoid/relations/builders/nested_attributes/one.rb +135 -0
  209. data/lib/mongoid/relations/builders/referenced/in.rb +26 -0
  210. data/lib/mongoid/relations/builders/referenced/many.rb +27 -0
  211. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +38 -0
  212. data/lib/mongoid/relations/builders/referenced/one.rb +26 -0
  213. data/lib/mongoid/relations/cascading.rb +56 -0
  214. data/lib/mongoid/relations/cascading/delete.rb +19 -0
  215. data/lib/mongoid/relations/cascading/destroy.rb +26 -0
  216. data/lib/mongoid/relations/cascading/nullify.rb +18 -0
  217. data/lib/mongoid/relations/cascading/strategy.rb +26 -0
  218. data/lib/mongoid/relations/constraint.rb +42 -0
  219. data/lib/mongoid/relations/conversions.rb +35 -0
  220. data/lib/mongoid/relations/cyclic.rb +103 -0
  221. data/lib/mongoid/relations/embedded/atomic.rb +89 -0
  222. data/lib/mongoid/relations/embedded/atomic/operation.rb +63 -0
  223. data/lib/mongoid/relations/embedded/atomic/pull.rb +65 -0
  224. data/lib/mongoid/relations/embedded/atomic/push_all.rb +59 -0
  225. data/lib/mongoid/relations/embedded/atomic/set.rb +61 -0
  226. data/lib/mongoid/relations/embedded/atomic/unset.rb +41 -0
  227. data/lib/mongoid/relations/embedded/in.rb +220 -0
  228. data/lib/mongoid/relations/embedded/many.rb +560 -0
  229. data/lib/mongoid/relations/embedded/one.rb +206 -0
  230. data/lib/mongoid/relations/embedded/sort.rb +31 -0
  231. data/lib/mongoid/relations/macros.rb +310 -0
  232. data/lib/mongoid/relations/many.rb +135 -0
  233. data/lib/mongoid/relations/metadata.rb +919 -0
  234. data/lib/mongoid/relations/nested_builder.rb +75 -0
  235. data/lib/mongoid/relations/one.rb +36 -0
  236. data/lib/mongoid/relations/options.rb +47 -0
  237. data/lib/mongoid/relations/polymorphic.rb +40 -0
  238. data/lib/mongoid/relations/proxy.rb +145 -0
  239. data/lib/mongoid/relations/referenced/batch.rb +72 -0
  240. data/lib/mongoid/relations/referenced/batch/insert.rb +57 -0
  241. data/lib/mongoid/relations/referenced/in.rb +262 -0
  242. data/lib/mongoid/relations/referenced/many.rb +623 -0
  243. data/lib/mongoid/relations/referenced/many_to_many.rb +396 -0
  244. data/lib/mongoid/relations/referenced/one.rb +272 -0
  245. data/lib/mongoid/relations/reflections.rb +62 -0
  246. data/lib/mongoid/relations/synchronization.rb +153 -0
  247. data/lib/mongoid/relations/targets.rb +2 -0
  248. data/lib/mongoid/relations/targets/enumerable.rb +372 -0
  249. data/lib/mongoid/reloading.rb +91 -0
  250. data/lib/mongoid/safety.rb +105 -0
  251. data/lib/mongoid/scope.rb +31 -0
  252. data/lib/mongoid/serialization.rb +134 -0
  253. data/lib/mongoid/sharding.rb +61 -0
  254. data/lib/mongoid/state.rb +97 -0
  255. data/lib/mongoid/threaded.rb +530 -0
  256. data/lib/mongoid/threaded/lifecycle.rb +192 -0
  257. data/lib/mongoid/timestamps.rb +15 -0
  258. data/lib/mongoid/timestamps/created.rb +24 -0
  259. data/lib/mongoid/timestamps/timeless.rb +50 -0
  260. data/lib/mongoid/timestamps/updated.rb +26 -0
  261. data/lib/mongoid/validations.rb +140 -0
  262. data/lib/mongoid/validations/associated.rb +46 -0
  263. data/lib/mongoid/validations/uniqueness.rb +145 -0
  264. data/lib/mongoid/version.rb +4 -0
  265. data/lib/mongoid/versioning.rb +185 -0
  266. data/lib/rack/mongoid.rb +2 -0
  267. data/lib/rack/mongoid/middleware/identity_map.rb +38 -0
  268. data/lib/rails/generators/mongoid/config/config_generator.rb +25 -0
  269. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +20 -0
  270. data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
  271. data/lib/rails/generators/mongoid/model/templates/model.rb.tt +19 -0
  272. data/lib/rails/generators/mongoid/observer/observer_generator.rb +17 -0
  273. data/lib/rails/generators/mongoid/observer/templates/observer.rb.tt +4 -0
  274. data/lib/rails/generators/mongoid_generator.rb +70 -0
  275. data/lib/rails/mongoid.rb +91 -0
  276. metadata +465 -0
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+
4
+ # Adds multiple database support to documents.
5
+ module MultiDatabase
6
+ extend ActiveSupport::Concern
7
+
8
+ module ClassMethods #:nodoc:
9
+
10
+ # Gets the database from the class.
11
+ #
12
+ # @example Get the database.
13
+ # Model.database
14
+ #
15
+ # @return [ Mongo::DB ] The database.
16
+ def database; @database end
17
+
18
+ # Set the database name.
19
+ #
20
+ # @example Set the database name.
21
+ # Model.set_database(:testing)
22
+ #
23
+ # @param [ Symbol ] name The database name.
24
+ #
25
+ # @return [ String ] The database name.
26
+ def set_database(name)
27
+ @database = name.to_s
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,106 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+
4
+ # Adds Rails' multi-parameter attribute support to Mongoid.
5
+ #
6
+ # @todo: Durran: This module needs an overhaul.
7
+ module MultiParameterAttributes
8
+
9
+ module Errors #:nodoc:
10
+
11
+ # Raised when an error occurred while doing a mass assignment to an
12
+ # attribute through the <tt>attributes=</tt> method. The exception
13
+ # has an +attribute+ property that is the name of the offending attribute.
14
+ class AttributeAssignmentError < Mongoid::Errors::MongoidError
15
+ attr_reader :exception, :attribute
16
+
17
+ def initialize(message, exception, attribute)
18
+ @exception = exception
19
+ @attribute = attribute
20
+ @message = message
21
+ end
22
+ end
23
+
24
+ # Raised when there are multiple errors while doing a mass assignment
25
+ # through the +attributes+ method. The exception has an +errors+
26
+ # property that contains an array of AttributeAssignmentError
27
+ # objects, each corresponding to the error while assigning to an
28
+ # attribute.
29
+ class MultiparameterAssignmentErrors < Mongoid::Errors::MongoidError
30
+ attr_reader :errors
31
+
32
+ def initialize(errors)
33
+ @errors = errors
34
+ end
35
+ end
36
+ end
37
+
38
+ # Process the provided attributes casting them to their proper values if a
39
+ # field exists for them on the document. This will be limited to only the
40
+ # attributes provided in the suppied +Hash+ so that no extra nil values get
41
+ # put into the document's attributes.
42
+ #
43
+ # @example Process the attributes.
44
+ # person.process(:title => "sir", :age => 40)
45
+ #
46
+ # @param [ Hash ] attrs The attributes to set.
47
+ # @param [ Symbol ] role A role for scoped mass assignment.
48
+ # @param [ Boolean ] guard_protected_attributes False to skip mass assignment protection.
49
+ #
50
+ # @since 2.0.0.rc.7
51
+ def process(attrs = nil, role = :default, guard_protected_attributes = true)
52
+ if attrs
53
+ errors = []
54
+ attributes = {}
55
+ multi_parameter_attributes = {}
56
+
57
+ attrs.each_pair do |key, value|
58
+ if key =~ /^([^\(]+)\((\d+)([if])\)$/
59
+ key, index = $1, $2.to_i
60
+ (multi_parameter_attributes[key] ||= {})[index] = value.empty? ? nil : value.send("to_#{$3}")
61
+ else
62
+ attributes[key] = value
63
+ end
64
+ end
65
+
66
+ multi_parameter_attributes.each_pair do |key, values|
67
+ begin
68
+ values = (values.keys.min..values.keys.max).map { |i| values[i] }
69
+ field = self.class.fields[key]
70
+ attributes[key] = instantiate_object(field, values)
71
+ rescue => e
72
+ errors << Errors::AttributeAssignmentError.new(
73
+ "error on assignment #{values.inspect} to #{key}", e, key
74
+ )
75
+ end
76
+ end
77
+
78
+ unless errors.empty?
79
+ raise(
80
+ Errors::MultiparameterAssignmentErrors.new(errors),
81
+ "#{errors.size} error(s) on assignment of multiparameter attributes"
82
+ )
83
+ end
84
+
85
+ super attributes, role, guard_protected_attributes
86
+ else
87
+ super
88
+ end
89
+ end
90
+
91
+ protected
92
+
93
+ def instantiate_object(field, values_with_empty_parameters)
94
+ return nil if values_with_empty_parameters.all? { |v| v.nil? }
95
+ values = values_with_empty_parameters.collect { |v| v.nil? ? 1 : v }
96
+ klass = field.type
97
+ if klass == DateTime || klass == Date || klass == Time
98
+ field.serialize(values)
99
+ elsif klass
100
+ klass.new *values
101
+ else
102
+ values
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,146 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+
4
+ # This module contains the named scoping behaviour.
5
+ module NamedScope
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ class_attribute :scopes
10
+ self.scopes = {}
11
+ end
12
+
13
+ module ClassMethods #:nodoc:
14
+
15
+ # Gets either the last scope on the stack or creates a new criteria.
16
+ #
17
+ # @example Get the last or new.
18
+ # Person.scoping(true)
19
+ #
20
+ # @param [ true, false ] embedded Is this scope for an embedded doc?
21
+ # @param [ true, false ] scoped Are we applying default scoping?
22
+ #
23
+ # @return [ Criteria ] The last scope or a new one.
24
+ #
25
+ # @since 2.0.0
26
+ def criteria(embedded = false, scoped = true)
27
+ scope_stack.last || Criteria.new(self, embedded).tap do |crit|
28
+ return crit.fuse(default_scoping) if default_scoping && scoped
29
+ end
30
+ end
31
+
32
+ # Creates a named_scope for the +Document+, similar to ActiveRecord's
33
+ # named_scopes. +NamedScopes+ are proxied +Criteria+ objects that can be
34
+ # chained.
35
+ #
36
+ # @example Create named scopes.
37
+ #
38
+ # class Person
39
+ # include Mongoid::Document
40
+ # field :active, :type => Boolean
41
+ # field :count, :type => Integer
42
+ #
43
+ # scope :active, :where => { :active => true }
44
+ # scope :count_gt_one, :where => { :count.gt => 1 }
45
+ # scope :at_least_count, lambda { |count| { :where => { :count.gt => count } } }
46
+ # end
47
+ #
48
+ # @param [ Symbol ] name The name of the scope.
49
+ # @param [ Hash, Criteria ] conditions The conditions of the scope.
50
+ #
51
+ # @since 1.0.0
52
+ def scope(name, conditions = {}, &block)
53
+ name = name.to_sym
54
+ valid_scope_name?(name)
55
+ scopes[name] = Scope.new(conditions, &block)
56
+ (class << self; self; end).class_eval <<-EOT
57
+ def #{name}(*args)
58
+ scope = scopes[:#{name}]
59
+ scope.extend(criteria.fuse(scope.conditions.scoped(*args)))
60
+ end
61
+ EOT
62
+ end
63
+ alias :named_scope :scope
64
+
65
+ # Get a criteria object for the class, scoped to the default if defined.
66
+ #
67
+ # @example Get a scoped criteria.
68
+ # Person.scoped
69
+ #
70
+ # @param [ true, false ] embedded Is the criteria for embedded docs?
71
+ #
72
+ # @return [ Criteria ] The scoped criteria.
73
+ #
74
+ # @since 2.0.0
75
+ def scoped(embedded = false)
76
+ criteria(embedded, true)
77
+ end
78
+
79
+ # Initializes and returns the current scope stack.
80
+ #
81
+ # @example Get the scope stack.
82
+ # Person.scope_stack
83
+ #
84
+ # @return [ Array<Criteria> ] The scope stack.
85
+ #
86
+ # @since 1.0.0
87
+ def scope_stack
88
+ Threaded.scope_stack[object_id] ||= []
89
+ end
90
+
91
+ # Get a criteria object for the class, ignoring default scoping.
92
+ #
93
+ # @example Get an unscoped criteria.
94
+ # Person.scoped
95
+ #
96
+ # @param [ true, false ] embedded Is the criteria for embedded docs?
97
+ #
98
+ # @return [ Criteria ] The unscoped criteria.
99
+ #
100
+ # @since 2.0.0
101
+ def unscoped(embedded = false)
102
+ criteria(embedded, false)
103
+ end
104
+
105
+ # Pushes the provided criteria onto the scope stack, and removes it after the
106
+ # provided block is yielded.
107
+ #
108
+ # @example Yield to the criteria.
109
+ # Person.with_scope(criteria)
110
+ #
111
+ # @param [ Criteria ] criteria The criteria to apply.
112
+ #
113
+ # @return [ Criteria ] The yielded criteria.
114
+ #
115
+ # @since 1.0.0
116
+ def with_scope(criteria)
117
+ scope_stack = self.scope_stack
118
+ scope_stack << criteria
119
+ begin
120
+ yield criteria
121
+ ensure
122
+ scope_stack.pop
123
+ end
124
+ end
125
+
126
+ protected
127
+
128
+ # Warns if overriding another scope or method.
129
+ #
130
+ # @example Warn if name exists.
131
+ # Model.valid_scope_name?("test")
132
+ #
133
+ # @param [ String, Symbol ] name The name of the scope.
134
+ def valid_scope_name?(name)
135
+ if scopes[name] || respond_to?(name, true)
136
+ if Mongoid.logger
137
+ Mongoid.logger.warn(
138
+ "Creating scope :#{name}. " +
139
+ "Overwriting existing method #{self.name}.#{name}."
140
+ )
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,54 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+
4
+ # Mongoid's implementation of Rails' nested attributes.
5
+ module NestedAttributes
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ class_attribute :nested_attributes
10
+ self.nested_attributes = []
11
+ end
12
+
13
+ module ClassMethods #:nodoc:
14
+
15
+ REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |_, value| value.blank? } }
16
+
17
+ # Used when needing to update related models from a parent relation. Can
18
+ # be used on embedded or referenced relations.
19
+ #
20
+ # @example Defining nested attributes.
21
+ #
22
+ # class Person
23
+ # include Mongoid::Document
24
+ #
25
+ # embeds_many :addresses
26
+ # embeds_one :game
27
+ # references_many :posts
28
+ #
29
+ # accepts_nested_attributes_for :addresses, :game, :posts
30
+ # end
31
+ #
32
+ # @param [ Array<Symbol>, Hash ] *args A list of relation names, followed
33
+ # by a hash of options.
34
+ #
35
+ # @option *args [ true, false ] :allow_destroy Can deletion occur?
36
+ # @option *args [ Proc, Symbol ] :reject_if Block or symbol pointing to a class method to reject documents with.
37
+ # @option *args [ Integer ] :limit The max number to create.
38
+ # @option *args [ true, false ] :update_only Only update existing docs.
39
+ def accepts_nested_attributes_for(*args)
40
+ options = args.extract_options!
41
+ options[:reject_if] = REJECT_ALL_BLANK_PROC if options[:reject_if] == :all_blank
42
+ args.each do |name|
43
+ self.nested_attributes += [ "#{name}_attributes=" ]
44
+ define_method("#{name}_attributes=") do |attrs|
45
+ _assigning do
46
+ relation = relations[name.to_s]
47
+ relation.nested_builder(attrs, options).build(self)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,170 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+
4
+ # Observer classes respond to life cycle callbacks to implement trigger-like
5
+ # behavior outside the original class. This is a great way to reduce the
6
+ # clutter that normally comes when the model class is burdened with
7
+ # functionality that doesn't pertain to the core responsibility of the
8
+ # class. Mongoid's observers work similar to ActiveRecord's. Example:
9
+ #
10
+ # class CommentObserver < Mongoid::Observer
11
+ # def after_save(comment)
12
+ # Notifications.comment(
13
+ # "admin@do.com", "New comment was posted", comment
14
+ # ).deliver
15
+ # end
16
+ # end
17
+ #
18
+ # This Observer sends an email when a Comment#save is finished.
19
+ #
20
+ # class ContactObserver < Mongoid::Observer
21
+ # def after_create(contact)
22
+ # contact.logger.info('New contact added!')
23
+ # end
24
+ #
25
+ # def after_destroy(contact)
26
+ # contact.logger.warn("Contact with an id of #{contact.id} was destroyed!")
27
+ # end
28
+ # end
29
+ #
30
+ # This Observer uses logger to log when specific callbacks are triggered.
31
+ #
32
+ # == Observing a class that can't be inferred
33
+ #
34
+ # Observers will by default be mapped to the class with which they share a
35
+ # name. So CommentObserver will be tied to observing Comment,
36
+ # ProductManagerObserver to ProductManager, and so on. If you want to
37
+ # name your observer differently than the class you're interested in
38
+ # observing, you can use the Observer.observe class method which takes
39
+ # either the concrete class (Product) or a symbol for that class (:product):
40
+ #
41
+ # class AuditObserver < Mongoid::Observer
42
+ # observe :account
43
+ #
44
+ # def after_update(account)
45
+ # AuditTrail.new(account, "UPDATED")
46
+ # end
47
+ # end
48
+ #
49
+ # If the audit observer needs to watch more than one kind of object,
50
+ # this can be specified with multiple arguments:
51
+ #
52
+ # class AuditObserver < Mongoid::Observer
53
+ # observe :account, :balance
54
+ #
55
+ # def after_update(record)
56
+ # AuditTrail.new(record, "UPDATED")
57
+ # end
58
+ # end
59
+ #
60
+ # The AuditObserver will now act on both updates to Account and Balance
61
+ # by treating them both as records.
62
+ #
63
+ # == Available callback methods
64
+ #
65
+ # * after_initialize
66
+ # * before_validation
67
+ # * after_validation
68
+ # * before_create
69
+ # * around_create
70
+ # * after_create
71
+ # * before_update
72
+ # * around_update
73
+ # * after_update
74
+ # * before_save
75
+ # * around_save
76
+ # * after_save
77
+ # * before_destroy
78
+ # * around_destroy
79
+ # * after_destroy
80
+ #
81
+ # == Storing Observers in Rails
82
+ #
83
+ # If you're using Mongoid within Rails, observer classes are usually stored
84
+ # in +app/models+ with the naming convention of +app/models/audit_observer.rb+.
85
+ #
86
+ # == Configuration
87
+ #
88
+ # In order to activate an observer, list it in the +config.mongoid.observers+
89
+ # configuration setting in your +config/application.rb+ file.
90
+ #
91
+ # config.mongoid.observers = :comment_observer, :signup_observer
92
+ #
93
+ # Observers will not be invoked unless you define them in your
94
+ # application configuration.
95
+ #
96
+ # == Loading
97
+ #
98
+ # Observers register themselves with the model class that they observe,
99
+ # since it is the class that notifies them of events when they occur.
100
+ # As a side-effect, when an observer is loaded, its corresponding model
101
+ # class is loaded.
102
+ #
103
+ # Observers are loaded after the application initializers, so that
104
+ # observed models can make use of extensions. If by any chance you are
105
+ # using observed models in the initialization, you can
106
+ # still load their observers by calling +ModelObserver.instance+ before.
107
+ # Observers are singletons and that call instantiates and registers them.
108
+ class Observer < ActiveModel::Observer
109
+
110
+ # Instantiate the new observer. Will add all child observers as well.
111
+ #
112
+ # @example Instantiate the observer.
113
+ # Mongoid::Observer.new
114
+ #
115
+ # @since 2.0.0.rc.8
116
+ def initialize
117
+ super and observed_descendants.each { |klass| add_observer!(klass) }
118
+ end
119
+
120
+ protected
121
+
122
+ # Get all the child observers.
123
+ #
124
+ # @example Get the children.
125
+ # observer.observed_descendants
126
+ #
127
+ # @return [ Array<Class> ] The children.
128
+ #
129
+ # @since 2.0.0.rc.8
130
+ def observed_descendants
131
+ observed_classes.sum([]) { |klass| klass.descendants }
132
+ end
133
+
134
+ # Adds the specified observer to the class.
135
+ #
136
+ # @example Add the observer.
137
+ # observer.add_observer!(Document)
138
+ #
139
+ # @param [ Class ] klass The child observer to add.
140
+ #
141
+ # @since 2.0.0.rc.8
142
+ def add_observer!(klass)
143
+ super and define_callbacks(klass)
144
+ end
145
+
146
+ # Defines all the callbacks for each observer of the model.
147
+ #
148
+ # @example Define all the callbacks.
149
+ # observer.define_callbacks(Document)
150
+ #
151
+ # @param [ Class ] klass The model to define them on.
152
+ #
153
+ # @since 2.0.0.rc.8
154
+ def define_callbacks(klass)
155
+ tap do |observer|
156
+ observer_name = observer.class.name.underscore.gsub('/', '__')
157
+ Mongoid::Callbacks::CALLBACKS.each do |callback|
158
+ next unless respond_to?(callback)
159
+ callback_meth = :"_notify_#{observer_name}_for_#{callback}"
160
+ unless klass.respond_to?(callback_meth)
161
+ klass.send(:define_method, callback_meth) do |&block|
162
+ observer.send(callback, self, &block)
163
+ end
164
+ klass.send(callback, callback_meth)
165
+ end
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end