mongoid-braxton 2.0.2

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 (226) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +50 -0
  3. data/Rakefile +51 -0
  4. data/lib/config/locales/bg.yml +41 -0
  5. data/lib/config/locales/de.yml +41 -0
  6. data/lib/config/locales/en.yml +45 -0
  7. data/lib/config/locales/es.yml +41 -0
  8. data/lib/config/locales/fr.yml +42 -0
  9. data/lib/config/locales/hu.yml +44 -0
  10. data/lib/config/locales/id.yml +46 -0
  11. data/lib/config/locales/it.yml +39 -0
  12. data/lib/config/locales/ja.yml +40 -0
  13. data/lib/config/locales/kr.yml +65 -0
  14. data/lib/config/locales/nl.yml +39 -0
  15. data/lib/config/locales/pl.yml +39 -0
  16. data/lib/config/locales/pt-BR.yml +40 -0
  17. data/lib/config/locales/pt.yml +40 -0
  18. data/lib/config/locales/ro.yml +46 -0
  19. data/lib/config/locales/ru.yml +41 -0
  20. data/lib/config/locales/sv.yml +40 -0
  21. data/lib/config/locales/vi.yml +45 -0
  22. data/lib/config/locales/zh-CN.yml +33 -0
  23. data/lib/mongoid.rb +140 -0
  24. data/lib/mongoid/atomicity.rb +111 -0
  25. data/lib/mongoid/attributes.rb +185 -0
  26. data/lib/mongoid/attributes/processing.rb +145 -0
  27. data/lib/mongoid/callbacks.rb +23 -0
  28. data/lib/mongoid/collection.rb +137 -0
  29. data/lib/mongoid/collections.rb +71 -0
  30. data/lib/mongoid/collections/master.rb +37 -0
  31. data/lib/mongoid/collections/operations.rb +42 -0
  32. data/lib/mongoid/collections/retry.rb +39 -0
  33. data/lib/mongoid/components.rb +45 -0
  34. data/lib/mongoid/config.rb +349 -0
  35. data/lib/mongoid/config/database.rb +167 -0
  36. data/lib/mongoid/config/replset_database.rb +78 -0
  37. data/lib/mongoid/contexts.rb +19 -0
  38. data/lib/mongoid/contexts/enumerable.rb +275 -0
  39. data/lib/mongoid/contexts/enumerable/sort.rb +43 -0
  40. data/lib/mongoid/contexts/mongo.rb +345 -0
  41. data/lib/mongoid/copyable.rb +46 -0
  42. data/lib/mongoid/criteria.rb +357 -0
  43. data/lib/mongoid/criterion/builder.rb +34 -0
  44. data/lib/mongoid/criterion/complex.rb +34 -0
  45. data/lib/mongoid/criterion/creational.rb +34 -0
  46. data/lib/mongoid/criterion/exclusion.rb +108 -0
  47. data/lib/mongoid/criterion/inclusion.rb +198 -0
  48. data/lib/mongoid/criterion/inspection.rb +22 -0
  49. data/lib/mongoid/criterion/optional.rb +193 -0
  50. data/lib/mongoid/criterion/selector.rb +143 -0
  51. data/lib/mongoid/criterion/unconvertable.rb +20 -0
  52. data/lib/mongoid/cursor.rb +86 -0
  53. data/lib/mongoid/default_scope.rb +36 -0
  54. data/lib/mongoid/dirty.rb +253 -0
  55. data/lib/mongoid/document.rb +284 -0
  56. data/lib/mongoid/errors.rb +13 -0
  57. data/lib/mongoid/errors/document_not_found.rb +29 -0
  58. data/lib/mongoid/errors/invalid_collection.rb +19 -0
  59. data/lib/mongoid/errors/invalid_database.rb +20 -0
  60. data/lib/mongoid/errors/invalid_field.rb +19 -0
  61. data/lib/mongoid/errors/invalid_options.rb +16 -0
  62. data/lib/mongoid/errors/invalid_type.rb +26 -0
  63. data/lib/mongoid/errors/mixed_relations.rb +37 -0
  64. data/lib/mongoid/errors/mongoid_error.rb +27 -0
  65. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +21 -0
  66. data/lib/mongoid/errors/unsaved_document.rb +23 -0
  67. data/lib/mongoid/errors/unsupported_version.rb +21 -0
  68. data/lib/mongoid/errors/validations.rb +24 -0
  69. data/lib/mongoid/extensions.rb +123 -0
  70. data/lib/mongoid/extensions/array/conversions.rb +23 -0
  71. data/lib/mongoid/extensions/array/parentization.rb +13 -0
  72. data/lib/mongoid/extensions/big_decimal/conversions.rb +19 -0
  73. data/lib/mongoid/extensions/binary/conversions.rb +17 -0
  74. data/lib/mongoid/extensions/boolean/conversions.rb +27 -0
  75. data/lib/mongoid/extensions/date/conversions.rb +25 -0
  76. data/lib/mongoid/extensions/datetime/conversions.rb +12 -0
  77. data/lib/mongoid/extensions/false_class/equality.rb +13 -0
  78. data/lib/mongoid/extensions/float/conversions.rb +20 -0
  79. data/lib/mongoid/extensions/hash/conversions.rb +19 -0
  80. data/lib/mongoid/extensions/hash/criteria_helpers.rb +22 -0
  81. data/lib/mongoid/extensions/hash/scoping.rb +12 -0
  82. data/lib/mongoid/extensions/integer/conversions.rb +20 -0
  83. data/lib/mongoid/extensions/nil/collectionization.rb +12 -0
  84. data/lib/mongoid/extensions/object/checks.rb +32 -0
  85. data/lib/mongoid/extensions/object/conversions.rb +25 -0
  86. data/lib/mongoid/extensions/object/reflections.rb +17 -0
  87. data/lib/mongoid/extensions/object/yoda.rb +27 -0
  88. data/lib/mongoid/extensions/object_id/conversions.rb +96 -0
  89. data/lib/mongoid/extensions/proc/scoping.rb +12 -0
  90. data/lib/mongoid/extensions/range/conversions.rb +25 -0
  91. data/lib/mongoid/extensions/set/conversions.rb +20 -0
  92. data/lib/mongoid/extensions/string/conversions.rb +34 -0
  93. data/lib/mongoid/extensions/string/inflections.rb +97 -0
  94. data/lib/mongoid/extensions/symbol/conversions.rb +21 -0
  95. data/lib/mongoid/extensions/symbol/inflections.rb +40 -0
  96. data/lib/mongoid/extensions/time_conversions.rb +38 -0
  97. data/lib/mongoid/extensions/true_class/equality.rb +13 -0
  98. data/lib/mongoid/extras.rb +42 -0
  99. data/lib/mongoid/factory.rb +37 -0
  100. data/lib/mongoid/field.rb +162 -0
  101. data/lib/mongoid/fields.rb +183 -0
  102. data/lib/mongoid/finders.rb +127 -0
  103. data/lib/mongoid/hierarchy.rb +85 -0
  104. data/lib/mongoid/identity.rb +92 -0
  105. data/lib/mongoid/indexes.rb +38 -0
  106. data/lib/mongoid/inspection.rb +54 -0
  107. data/lib/mongoid/javascript.rb +21 -0
  108. data/lib/mongoid/javascript/functions.yml +37 -0
  109. data/lib/mongoid/json.rb +16 -0
  110. data/lib/mongoid/keys.rb +131 -0
  111. data/lib/mongoid/logger.rb +18 -0
  112. data/lib/mongoid/matchers.rb +32 -0
  113. data/lib/mongoid/matchers/all.rb +11 -0
  114. data/lib/mongoid/matchers/default.rb +70 -0
  115. data/lib/mongoid/matchers/exists.rb +13 -0
  116. data/lib/mongoid/matchers/gt.rb +11 -0
  117. data/lib/mongoid/matchers/gte.rb +11 -0
  118. data/lib/mongoid/matchers/in.rb +11 -0
  119. data/lib/mongoid/matchers/lt.rb +11 -0
  120. data/lib/mongoid/matchers/lte.rb +11 -0
  121. data/lib/mongoid/matchers/ne.rb +11 -0
  122. data/lib/mongoid/matchers/nin.rb +11 -0
  123. data/lib/mongoid/matchers/or.rb +30 -0
  124. data/lib/mongoid/matchers/size.rb +11 -0
  125. data/lib/mongoid/matchers/strategies.rb +63 -0
  126. data/lib/mongoid/multi_database.rb +11 -0
  127. data/lib/mongoid/multi_parameter_attributes.rb +82 -0
  128. data/lib/mongoid/named_scope.rb +137 -0
  129. data/lib/mongoid/nested_attributes.rb +51 -0
  130. data/lib/mongoid/observer.rb +67 -0
  131. data/lib/mongoid/paranoia.rb +103 -0
  132. data/lib/mongoid/paths.rb +61 -0
  133. data/lib/mongoid/persistence.rb +240 -0
  134. data/lib/mongoid/persistence/atomic.rb +88 -0
  135. data/lib/mongoid/persistence/atomic/add_to_set.rb +32 -0
  136. data/lib/mongoid/persistence/atomic/inc.rb +28 -0
  137. data/lib/mongoid/persistence/atomic/operation.rb +44 -0
  138. data/lib/mongoid/persistence/atomic/pull_all.rb +33 -0
  139. data/lib/mongoid/persistence/atomic/push.rb +28 -0
  140. data/lib/mongoid/persistence/command.rb +71 -0
  141. data/lib/mongoid/persistence/insert.rb +53 -0
  142. data/lib/mongoid/persistence/insert_embedded.rb +43 -0
  143. data/lib/mongoid/persistence/remove.rb +44 -0
  144. data/lib/mongoid/persistence/remove_all.rb +40 -0
  145. data/lib/mongoid/persistence/remove_embedded.rb +48 -0
  146. data/lib/mongoid/persistence/update.rb +77 -0
  147. data/lib/mongoid/railtie.rb +139 -0
  148. data/lib/mongoid/railties/database.rake +171 -0
  149. data/lib/mongoid/railties/document.rb +12 -0
  150. data/lib/mongoid/relations.rb +107 -0
  151. data/lib/mongoid/relations/accessors.rb +175 -0
  152. data/lib/mongoid/relations/auto_save.rb +34 -0
  153. data/lib/mongoid/relations/binding.rb +26 -0
  154. data/lib/mongoid/relations/bindings.rb +9 -0
  155. data/lib/mongoid/relations/bindings/embedded/in.rb +82 -0
  156. data/lib/mongoid/relations/bindings/embedded/many.rb +98 -0
  157. data/lib/mongoid/relations/bindings/embedded/one.rb +66 -0
  158. data/lib/mongoid/relations/bindings/referenced/in.rb +74 -0
  159. data/lib/mongoid/relations/bindings/referenced/many.rb +96 -0
  160. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +103 -0
  161. data/lib/mongoid/relations/bindings/referenced/one.rb +66 -0
  162. data/lib/mongoid/relations/builder.rb +42 -0
  163. data/lib/mongoid/relations/builders.rb +79 -0
  164. data/lib/mongoid/relations/builders/embedded/in.rb +25 -0
  165. data/lib/mongoid/relations/builders/embedded/many.rb +32 -0
  166. data/lib/mongoid/relations/builders/embedded/one.rb +26 -0
  167. data/lib/mongoid/relations/builders/nested_attributes/many.rb +126 -0
  168. data/lib/mongoid/relations/builders/nested_attributes/one.rb +135 -0
  169. data/lib/mongoid/relations/builders/referenced/in.rb +29 -0
  170. data/lib/mongoid/relations/builders/referenced/many.rb +47 -0
  171. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +29 -0
  172. data/lib/mongoid/relations/builders/referenced/one.rb +27 -0
  173. data/lib/mongoid/relations/cascading.rb +55 -0
  174. data/lib/mongoid/relations/cascading/delete.rb +19 -0
  175. data/lib/mongoid/relations/cascading/destroy.rb +19 -0
  176. data/lib/mongoid/relations/cascading/nullify.rb +18 -0
  177. data/lib/mongoid/relations/cascading/strategy.rb +26 -0
  178. data/lib/mongoid/relations/constraint.rb +42 -0
  179. data/lib/mongoid/relations/cyclic.rb +103 -0
  180. data/lib/mongoid/relations/embedded/atomic.rb +86 -0
  181. data/lib/mongoid/relations/embedded/atomic/operation.rb +63 -0
  182. data/lib/mongoid/relations/embedded/atomic/pull.rb +65 -0
  183. data/lib/mongoid/relations/embedded/atomic/push_all.rb +59 -0
  184. data/lib/mongoid/relations/embedded/atomic/set.rb +61 -0
  185. data/lib/mongoid/relations/embedded/atomic/unset.rb +41 -0
  186. data/lib/mongoid/relations/embedded/in.rb +173 -0
  187. data/lib/mongoid/relations/embedded/many.rb +499 -0
  188. data/lib/mongoid/relations/embedded/one.rb +170 -0
  189. data/lib/mongoid/relations/macros.rb +310 -0
  190. data/lib/mongoid/relations/many.rb +215 -0
  191. data/lib/mongoid/relations/metadata.rb +539 -0
  192. data/lib/mongoid/relations/nested_builder.rb +68 -0
  193. data/lib/mongoid/relations/one.rb +47 -0
  194. data/lib/mongoid/relations/polymorphic.rb +54 -0
  195. data/lib/mongoid/relations/proxy.rb +143 -0
  196. data/lib/mongoid/relations/referenced/batch.rb +71 -0
  197. data/lib/mongoid/relations/referenced/batch/insert.rb +57 -0
  198. data/lib/mongoid/relations/referenced/in.rb +216 -0
  199. data/lib/mongoid/relations/referenced/many.rb +516 -0
  200. data/lib/mongoid/relations/referenced/many_to_many.rb +396 -0
  201. data/lib/mongoid/relations/referenced/one.rb +222 -0
  202. data/lib/mongoid/relations/reflections.rb +45 -0
  203. data/lib/mongoid/safe.rb +23 -0
  204. data/lib/mongoid/safety.rb +207 -0
  205. data/lib/mongoid/scope.rb +31 -0
  206. data/lib/mongoid/serialization.rb +99 -0
  207. data/lib/mongoid/sharding.rb +51 -0
  208. data/lib/mongoid/state.rb +67 -0
  209. data/lib/mongoid/timestamps.rb +14 -0
  210. data/lib/mongoid/timestamps/created.rb +31 -0
  211. data/lib/mongoid/timestamps/updated.rb +33 -0
  212. data/lib/mongoid/validations.rb +124 -0
  213. data/lib/mongoid/validations/associated.rb +44 -0
  214. data/lib/mongoid/validations/referenced.rb +58 -0
  215. data/lib/mongoid/validations/uniqueness.rb +85 -0
  216. data/lib/mongoid/version.rb +4 -0
  217. data/lib/mongoid/versioning.rb +113 -0
  218. data/lib/rails/generators/mongoid/config/config_generator.rb +25 -0
  219. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +20 -0
  220. data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
  221. data/lib/rails/generators/mongoid/model/templates/model.rb +19 -0
  222. data/lib/rails/generators/mongoid/observer/observer_generator.rb +17 -0
  223. data/lib/rails/generators/mongoid/observer/templates/observer.rb +4 -0
  224. data/lib/rails/generators/mongoid_generator.rb +70 -0
  225. data/lib/rails/mongoid.rb +58 -0
  226. metadata +406 -0
@@ -0,0 +1,11 @@
1
+ module Mongoid::MultiDatabase
2
+ extend ActiveSupport::Concern
3
+
4
+ module ClassMethods
5
+
6
+ def database; @database end
7
+ def set_database(name)
8
+ @database = name.to_s
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,82 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+
4
+ # @todo: Durran: This module needs an overhaul.
5
+ module MultiParameterAttributes
6
+ module Errors
7
+ # Raised when an error occurred while doing a mass assignment to an attribute through the
8
+ # <tt>attributes=</tt> method. The exception has an +attribute+ property that is the name of the
9
+ # offending attribute.
10
+ class AttributeAssignmentError < Mongoid::Errors::MongoidError
11
+ attr_reader :exception, :attribute
12
+ def initialize(message, exception, attribute)
13
+ @exception = exception
14
+ @attribute = attribute
15
+ @message = message
16
+ end
17
+ end
18
+
19
+ # Raised when there are multiple errors while doing a mass assignment through the +attributes+
20
+ # method. The exception has an +errors+ property that contains an array of AttributeAssignmentError
21
+ # objects, each corresponding to the error while assigning to an attribute.
22
+ class MultiparameterAssignmentErrors < Mongoid::Errors::MongoidError
23
+ attr_reader :errors
24
+ def initialize(errors)
25
+ @errors = errors
26
+ end
27
+ end
28
+ end
29
+
30
+ def process(attrs = nil, guard_protected_attributes = true)
31
+ if attrs
32
+ errors = []
33
+ attributes = {}
34
+ multi_parameter_attributes = {}
35
+
36
+ attrs.each_pair do |key, value|
37
+ if key =~ /^([^\(]+)\((\d+)([if])\)$/
38
+ key, index = $1, $2.to_i
39
+ (multi_parameter_attributes[key] ||= {})[index] = value.empty? ? nil : value.send("to_#{$3}")
40
+ else
41
+ attributes[key] = value
42
+ end
43
+ end
44
+
45
+ multi_parameter_attributes.each_pair do |key, values|
46
+ begin
47
+ values = (values.keys.min..values.keys.max).map { |i| values[i] }
48
+ klass = self.class.fields[key].try(:type)
49
+ attributes[key] = instantiate_object(klass, values)
50
+ rescue => e
51
+ errors << Errors::AttributeAssignmentError.new("error on assignment #{values.inspect} to #{key}", e, key)
52
+ end
53
+ end
54
+
55
+ unless errors.empty?
56
+ raise Errors::MultiparameterAssignmentErrors.new(errors), "#{errors.size} error(s) on assignment of multiparameter attributes"
57
+ end
58
+
59
+ super attributes, guard_protected_attributes
60
+ else
61
+ super
62
+ end
63
+ end
64
+
65
+ protected
66
+
67
+ def instantiate_object(klass, values_with_empty_parameters)
68
+ return nil if values_with_empty_parameters.all? { |v| v.nil? }
69
+
70
+ values = values_with_empty_parameters.collect { |v| v.nil? ? 1 : v }
71
+
72
+ if klass == DateTime || klass == Date || klass == Time
73
+ klass.send(:convert_to_time, values)
74
+ elsif klass
75
+ klass.new *values
76
+ else
77
+ values
78
+ end
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,137 @@
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
+ scope_stack_for = Thread.current[:mongoid_scope_stack] ||= {}
89
+ scope_stack_for[object_id] ||= []
90
+ end
91
+
92
+ # Get a criteria object for the class, ignoring default scoping.
93
+ #
94
+ # @example Get an unscoped criteria.
95
+ # Person.scoped
96
+ #
97
+ # @param [ true, false ] embedded Is the criteria for embedded docs?
98
+ #
99
+ # @return [ Criteria ] The unscoped criteria.
100
+ #
101
+ # @since 2.0.0
102
+ def unscoped(embedded = false)
103
+ criteria(embedded, false)
104
+ end
105
+
106
+ # Pushes the provided criteria onto the scope stack, and removes it after the
107
+ # provided block is yielded.
108
+ #
109
+ # @example Yield to the criteria.
110
+ # Person.with_scope(criteria)
111
+ #
112
+ # @param [ Criteria ] criteria The criteria to apply.
113
+ #
114
+ # @return [ Criteria ] The yielded criteria.
115
+ #
116
+ # @since 1.0.0
117
+ def with_scope(criteria)
118
+ scope_stack = self.scope_stack
119
+ scope_stack << criteria
120
+ begin
121
+ yield criteria
122
+ ensure
123
+ scope_stack.pop
124
+ end
125
+ end
126
+
127
+ protected
128
+
129
+ def valid_scope_name?(name)
130
+ if !scopes[name] && respond_to?(name, true)
131
+ Mongoid.logger.warn "Creating scope :#{name}. " \
132
+ "Overwriting existing method #{self.name}.#{name}." if Mongoid.logger
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module NestedAttributes
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ class_attribute :nested_attributes
8
+ self.nested_attributes = []
9
+
10
+ delegate :nested_attributes, :to => "self.class"
11
+ end
12
+
13
+ module ClassMethods
14
+ REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |_, value| value.blank? } }
15
+
16
+ # Used when needing to update related models from a parent relation. Can
17
+ # be used on embedded or referenced relations.
18
+ #
19
+ # @example Defining nested attributes.
20
+ #
21
+ # class Person
22
+ # include Mongoid::Document
23
+ #
24
+ # embeds_many :addresses
25
+ # embeds_one :game
26
+ # references_many :posts
27
+ #
28
+ # accepts_nested_attributes_for :addresses, :game, :posts
29
+ # end
30
+ #
31
+ # @param [ Array<Symbol>, Hash ] *args A list of relation names, followed
32
+ # by a hash of options.
33
+ #
34
+ # @option *args [ true, false ] :allow_destroy Can deletion occur?
35
+ # @option *args [ Proc ] :reject_if Block to reject documents with.
36
+ # @option *args [ Integer ] :limit The max number to create.
37
+ # @option *args [ true, false ] :update_only Only update existing docs.
38
+ def accepts_nested_attributes_for(*args)
39
+ options = args.extract_options!
40
+ options[:reject_if] = REJECT_ALL_BLANK_PROC if options[:reject_if] == :all_blank
41
+ args.each do |name|
42
+ self.nested_attributes += [ "#{name}_attributes=" ]
43
+ define_method("#{name}_attributes=") do |attrs|
44
+ relation = relations[name.to_s]
45
+ relation.nested_builder(attrs, options).build(self)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,67 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+
4
+ # Mongoid observers hook into the lifecycle of documents.
5
+ class Observer < ActiveModel::Observer
6
+
7
+ # Instantiate the new observer. Will add all child observers as well.
8
+ #
9
+ # @example Instantiate the observer.
10
+ # Mongoid::Observer.new
11
+ #
12
+ # @since 2.0.0
13
+ def initialize
14
+ super and observed_descendants.each { |klass| add_observer!(klass) }
15
+ end
16
+
17
+ protected
18
+
19
+ # Get all the child observers.
20
+ #
21
+ # @example Get the children.
22
+ # observer.observed_descendants
23
+ #
24
+ # @return [ Array<Class> ] The children.
25
+ #
26
+ # @since 2.0.0
27
+ def observed_descendants
28
+ observed_classes.sum([]) { |klass| klass.descendants }
29
+ end
30
+
31
+ # Adds the specified observer to the class.
32
+ #
33
+ # @example Add the observer.
34
+ # observer.add_observer!(Document)
35
+ #
36
+ # @param [ Class ] klass The child observer to add.
37
+ #
38
+ # @since 2.0.0
39
+ def add_observer!(klass)
40
+ super and define_callbacks(klass)
41
+ end
42
+
43
+ # Defines all the callbacks for each observer of the model.
44
+ #
45
+ # @example Define all the callbacks.
46
+ # observer.define_callbacks(Document)
47
+ #
48
+ # @param [ Class ] klass The model to define them on.
49
+ #
50
+ # @since 2.0.0
51
+ def define_callbacks(klass)
52
+ tap do |observer|
53
+ observer_name = observer.class.name.underscore.gsub('/', '__')
54
+ Mongoid::Callbacks::CALLBACKS.each do |callback|
55
+ next unless respond_to?(callback)
56
+ callback_meth = :"_notify_#{observer_name}_for_#{callback}"
57
+ unless klass.respond_to?(callback_meth)
58
+ klass.send(:define_method, callback_meth) do |&block|
59
+ observer.send(callback, self, &block)
60
+ end
61
+ klass.send(callback, callback_meth)
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,103 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ # Include this module to get soft deletion of root level documents.
4
+ # This will add a deleted_at field to the +Document+, managed automatically.
5
+ # Potentially incompatible with unique indices. (if collisions with deleted items)
6
+ #
7
+ # To use:
8
+ #
9
+ # class Person
10
+ # include Mongoid::Document
11
+ # include Mongoid::Paranoia
12
+ # end
13
+ module Paranoia
14
+ extend ActiveSupport::Concern
15
+
16
+ included do
17
+ field :deleted_at, :type => Time
18
+ end
19
+
20
+ # Delete the paranoid +Document+ from the database completely. This will
21
+ # run the destroy callbacks.
22
+ #
23
+ # Example:
24
+ #
25
+ # <tt>document.destroy!</tt>
26
+ def destroy!
27
+ run_callbacks(:destroy) { delete! }
28
+ end
29
+
30
+ # Delete the paranoid +Document+ from the database completely.
31
+ #
32
+ # Example:
33
+ #
34
+ # <tt>document.delete!</tt>
35
+ def delete!
36
+ @destroyed = true
37
+ Mongoid::Persistence::Remove.new(self).persist
38
+ end
39
+
40
+ # Delete the +Document+, will set the deleted_at timestamp and not actually
41
+ # delete it.
42
+ #
43
+ # Example:
44
+ #
45
+ # <tt>document.remove</tt>
46
+ #
47
+ # Returns:
48
+ #
49
+ # true
50
+ def remove(options = {})
51
+ now = Time.now
52
+ collection.update({ :_id => id }, { '$set' => { :deleted_at => now } })
53
+ @attributes["deleted_at"] = now
54
+ true
55
+ end
56
+
57
+ alias :delete :remove
58
+
59
+ # Determines if this document is destroyed.
60
+ #
61
+ # Returns:
62
+ #
63
+ # true if the +Document+ was destroyed.
64
+ def destroyed?
65
+ @destroyed || !!deleted_at
66
+ end
67
+
68
+ # Restores a previously soft-deleted document. Handles this by removing the
69
+ # deleted_at flag.
70
+ #
71
+ # Example:
72
+ #
73
+ # <tt>document.restore</tt>
74
+ def restore
75
+ collection.update({ :_id => id }, { '$unset' => { :deleted_at => true } })
76
+ @attributes.delete("deleted_at")
77
+ end
78
+
79
+ module ClassMethods #:nodoc:
80
+
81
+ # Override the default +Criteria+ accessor to only get existing
82
+ # documents. Passes all arguments up to +NamedScope.criteria+
83
+ #
84
+ # Returns:
85
+ #
86
+ # A +Criteria+ for deleted_at not existing.
87
+ def criteria(*args)
88
+ super.where(:deleted_at.exists => false)
89
+ end
90
+
91
+ # Find deleted documents
92
+ #
93
+ # Examples:
94
+ #
95
+ # <tt>Person.deleted</tt> # all deleted employees
96
+ # <tt>Company.first.employees.deleted</tt> # works with a join
97
+ # <tt>Person.deleted.find("4c188dea7b17235a2a000001").first</tt>
98
+ def deleted
99
+ where(:deleted_at.exists => true)
100
+ end
101
+ end
102
+ end
103
+ end