mongo_mapper 0.12.0 → 0.13.0.beta1

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 (154) hide show
  1. checksums.yaml +7 -0
  2. data/README.rdoc +35 -13
  3. data/bin/mmconsole +1 -1
  4. data/lib/mongo_mapper.rb +4 -0
  5. data/lib/mongo_mapper/connection.rb +17 -6
  6. data/lib/mongo_mapper/document.rb +1 -0
  7. data/lib/mongo_mapper/exceptions.rb +4 -1
  8. data/lib/mongo_mapper/extensions/binary.rb +1 -1
  9. data/lib/mongo_mapper/extensions/boolean.rb +20 -23
  10. data/lib/mongo_mapper/extensions/date.rb +3 -3
  11. data/lib/mongo_mapper/extensions/integer.rb +5 -1
  12. data/lib/mongo_mapper/extensions/kernel.rb +2 -0
  13. data/lib/mongo_mapper/extensions/ordered_hash.rb +23 -0
  14. data/lib/mongo_mapper/extensions/string.rb +2 -2
  15. data/lib/mongo_mapper/extensions/time.rb +7 -5
  16. data/lib/mongo_mapper/middleware/identity_map.rb +3 -4
  17. data/lib/mongo_mapper/plugins.rb +1 -1
  18. data/lib/mongo_mapper/plugins/associations.rb +11 -5
  19. data/lib/mongo_mapper/plugins/associations/base.rb +5 -3
  20. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +0 -0
  21. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +8 -8
  22. data/lib/mongo_mapper/plugins/associations/collection.rb +2 -0
  23. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +32 -7
  24. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +2 -2
  25. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +12 -12
  26. data/lib/mongo_mapper/plugins/associations/proxy.rb +5 -1
  27. data/lib/mongo_mapper/plugins/associations/single_association.rb +6 -6
  28. data/lib/mongo_mapper/plugins/clone.rb +4 -2
  29. data/lib/mongo_mapper/plugins/dirty.rb +22 -21
  30. data/lib/mongo_mapper/plugins/document.rb +4 -4
  31. data/lib/mongo_mapper/plugins/dumpable.rb +22 -0
  32. data/lib/mongo_mapper/plugins/embedded_callbacks.rb +58 -9
  33. data/lib/mongo_mapper/plugins/identity_map.rb +42 -32
  34. data/lib/mongo_mapper/plugins/keys.rb +133 -54
  35. data/lib/mongo_mapper/plugins/keys/key.rb +68 -22
  36. data/lib/mongo_mapper/plugins/modifiers.rb +26 -19
  37. data/lib/mongo_mapper/plugins/persistence.rb +15 -5
  38. data/lib/mongo_mapper/plugins/querying.rb +15 -40
  39. data/lib/mongo_mapper/plugins/querying/{decorator.rb → decorated_plucky_query.rb} +24 -4
  40. data/lib/mongo_mapper/plugins/rails.rb +22 -2
  41. data/lib/mongo_mapper/plugins/safe.rb +8 -5
  42. data/lib/mongo_mapper/plugins/sci.rb +26 -4
  43. data/lib/mongo_mapper/plugins/scopes.rb +5 -4
  44. data/lib/mongo_mapper/plugins/timestamps.rb +11 -4
  45. data/lib/mongo_mapper/plugins/validations.rb +1 -1
  46. data/lib/mongo_mapper/utils.rb +12 -0
  47. data/lib/mongo_mapper/version.rb +1 -1
  48. data/lib/rails/generators/mongo_mapper/config/config_generator.rb +20 -7
  49. data/lib/rails/generators/mongo_mapper/config/templates/mongo.yml +6 -0
  50. data/lib/rails/generators/mongo_mapper/model/model_generator.rb +18 -1
  51. data/lib/rails/generators/mongo_mapper/model/templates/model.rb +9 -5
  52. data/{test/functional/test_accessible.rb → spec/functional/accessible_spec.rb} +29 -29
  53. data/{test/functional/associations/test_belongs_to_polymorphic_proxy.rb → spec/functional/associations/belongs_to_polymorphic_proxy_spec.rb} +10 -10
  54. data/{test/functional/associations/test_belongs_to_proxy.rb → spec/functional/associations/belongs_to_proxy_spec.rb} +82 -64
  55. data/{test/functional/associations/test_in_array_proxy.rb → spec/functional/associations/in_array_proxy_spec.rb} +68 -68
  56. data/{test/functional/associations/test_many_documents_as_proxy.rb → spec/functional/associations/many_documents_as_proxy_spec.rb} +37 -38
  57. data/{test/functional/associations/test_many_documents_proxy.rb → spec/functional/associations/many_documents_proxy_spec.rb} +233 -146
  58. data/{test/functional/associations/test_many_embedded_polymorphic_proxy.rb → spec/functional/associations/many_embedded_polymorphic_proxy_spec.rb} +19 -20
  59. data/{test/functional/associations/test_many_embedded_proxy.rb → spec/functional/associations/many_embedded_proxy_spec.rb} +23 -24
  60. data/{test/functional/associations/test_many_polymorphic_proxy.rb → spec/functional/associations/many_polymorphic_proxy_spec.rb} +45 -46
  61. data/{test/functional/associations/test_one_as_proxy.rb → spec/functional/associations/one_as_proxy_spec.rb} +75 -77
  62. data/{test/functional/associations/test_one_embedded_polymorphic_proxy.rb → spec/functional/associations/one_embedded_polymorphic_proxy_spec.rb} +31 -32
  63. data/{test/functional/associations/test_one_embedded_proxy.rb → spec/functional/associations/one_embedded_proxy_spec.rb} +10 -10
  64. data/{test/functional/associations/test_one_proxy.rb → spec/functional/associations/one_proxy_spec.rb} +125 -102
  65. data/spec/functional/associations_spec.rb +48 -0
  66. data/{test/functional/test_binary.rb → spec/functional/binary_spec.rb} +6 -6
  67. data/spec/functional/caching_spec.rb +75 -0
  68. data/{test/functional/test_callbacks.rb → spec/functional/callbacks_spec.rb} +84 -26
  69. data/{test/functional/test_dirty.rb → spec/functional/dirty_spec.rb} +57 -42
  70. data/{test/functional/test_document.rb → spec/functional/document_spec.rb} +52 -52
  71. data/spec/functional/dumpable_spec.rb +24 -0
  72. data/{test/functional/test_dynamic_querying.rb → spec/functional/dynamic_querying_spec.rb} +14 -14
  73. data/{test/functional/test_embedded_document.rb → spec/functional/embedded_document_spec.rb} +51 -42
  74. data/{test/functional/test_equality.rb → spec/functional/equality_spec.rb} +4 -4
  75. data/spec/functional/extensions_spec.rb +16 -0
  76. data/{test/functional/test_identity_map.rb → spec/functional/identity_map_spec.rb} +73 -61
  77. data/spec/functional/indexes_spec.rb +48 -0
  78. data/spec/functional/keys_spec.rb +224 -0
  79. data/{test/functional/test_logger.rb → spec/functional/logger_spec.rb} +6 -6
  80. data/spec/functional/modifiers_spec.rb +550 -0
  81. data/spec/functional/pagination_spec.rb +89 -0
  82. data/spec/functional/protected_spec.rb +199 -0
  83. data/spec/functional/querying_spec.rb +1003 -0
  84. data/spec/functional/rails_spec.rb +55 -0
  85. data/spec/functional/safe_spec.rb +163 -0
  86. data/{test/functional/test_sci.rb → spec/functional/sci_spec.rb} +123 -34
  87. data/{test/functional/test_scopes.rb → spec/functional/scopes_spec.rb} +59 -26
  88. data/spec/functional/timestamps_spec.rb +97 -0
  89. data/{test/functional/test_touch.rb → spec/functional/touch_spec.rb} +13 -13
  90. data/spec/functional/userstamps_spec.rb +46 -0
  91. data/{test/functional/test_validations.rb → spec/functional/validations_spec.rb} +64 -64
  92. data/spec/spec_helper.rb +81 -0
  93. data/spec/support/matchers.rb +24 -0
  94. data/{test → spec/support}/models.rb +1 -6
  95. data/spec/unit/associations/base_spec.rb +146 -0
  96. data/spec/unit/associations/belongs_to_association_spec.rb +30 -0
  97. data/spec/unit/associations/many_association_spec.rb +64 -0
  98. data/spec/unit/associations/one_association_spec.rb +48 -0
  99. data/{test/unit/associations/test_proxy.rb → spec/unit/associations/proxy_spec.rb} +21 -21
  100. data/{test/unit/test_clone.rb → spec/unit/clone_spec.rb} +21 -11
  101. data/spec/unit/config_generator_spec.rb +24 -0
  102. data/{test/unit/test_document.rb → spec/unit/document_spec.rb} +42 -42
  103. data/{test/unit/test_dynamic_finder.rb → spec/unit/dynamic_finder_spec.rb} +28 -28
  104. data/{test/unit/test_embedded_document.rb → spec/unit/embedded_document_spec.rb} +102 -108
  105. data/{test/unit/test_equality.rb → spec/unit/equality_spec.rb} +7 -7
  106. data/{test/unit/test_exceptions.rb → spec/unit/exceptions_spec.rb} +3 -3
  107. data/{test/unit/test_extensions.rb → spec/unit/extensions_spec.rb} +85 -71
  108. data/spec/unit/identity_map_middleware_spec.rb +134 -0
  109. data/{test/unit/test_inspect.rb → spec/unit/inspect_spec.rb} +8 -8
  110. data/{test/unit/test_key.rb → spec/unit/key_spec.rb} +82 -52
  111. data/spec/unit/keys_spec.rb +155 -0
  112. data/spec/unit/model_generator_spec.rb +47 -0
  113. data/spec/unit/mongo_mapper_spec.rb +184 -0
  114. data/spec/unit/pagination_spec.rb +11 -0
  115. data/{test/unit/test_plugins.rb → spec/unit/plugins_spec.rb} +14 -14
  116. data/spec/unit/rails_compatibility_spec.rb +40 -0
  117. data/{test/unit/test_rails_reflect_on_association.rb → spec/unit/rails_reflect_on_association_spec.rb} +9 -9
  118. data/{test/unit/test_rails.rb → spec/unit/rails_spec.rb} +31 -31
  119. data/spec/unit/serialization_spec.rb +169 -0
  120. data/spec/unit/serializers/json_serializer_spec.rb +218 -0
  121. data/spec/unit/serializers/xml_serializer_spec.rb +198 -0
  122. data/{test/unit/test_time_zones.rb → spec/unit/time_zones_spec.rb} +8 -8
  123. data/{test/unit/test_translation.rb → spec/unit/translation_spec.rb} +6 -6
  124. data/{test/unit/test_validations.rb → spec/unit/validations_spec.rb} +72 -59
  125. metadata +199 -179
  126. data/test/_NOTE_ON_TESTING +0 -1
  127. data/test/functional/test_associations.rb +0 -46
  128. data/test/functional/test_caching.rb +0 -77
  129. data/test/functional/test_indexes.rb +0 -50
  130. data/test/functional/test_modifiers.rb +0 -537
  131. data/test/functional/test_pagination.rb +0 -91
  132. data/test/functional/test_protected.rb +0 -201
  133. data/test/functional/test_querying.rb +0 -935
  134. data/test/functional/test_safe.rb +0 -76
  135. data/test/functional/test_timestamps.rb +0 -62
  136. data/test/functional/test_userstamps.rb +0 -44
  137. data/test/support/railtie.rb +0 -4
  138. data/test/support/railtie/autoloaded.rb +0 -2
  139. data/test/support/railtie/not_autoloaded.rb +0 -3
  140. data/test/support/railtie/parent.rb +0 -3
  141. data/test/test_active_model_lint.rb +0 -18
  142. data/test/test_helper.rb +0 -93
  143. data/test/unit/associations/test_base.rb +0 -146
  144. data/test/unit/associations/test_belongs_to_association.rb +0 -29
  145. data/test/unit/associations/test_many_association.rb +0 -63
  146. data/test/unit/associations/test_one_association.rb +0 -47
  147. data/test/unit/serializers/test_json_serializer.rb +0 -216
  148. data/test/unit/serializers/test_xml_serializer.rb +0 -196
  149. data/test/unit/test_identity_map_middleware.rb +0 -132
  150. data/test/unit/test_keys.rb +0 -65
  151. data/test/unit/test_mongo_mapper.rb +0 -157
  152. data/test/unit/test_pagination.rb +0 -11
  153. data/test/unit/test_rails_compatibility.rb +0 -38
  154. data/test/unit/test_serialization.rb +0 -166
@@ -71,64 +71,71 @@ module MongoMapper
71
71
  collection.update(criteria, {modifier => updates}, options.merge(:multi => true))
72
72
  else
73
73
  collection.update(criteria, {modifier => updates}, :multi => true)
74
- end
74
+ end
75
75
  end
76
76
 
77
77
  def criteria_and_keys_from_args(args)
78
78
  if args[0].is_a?(Hash)
79
79
  criteria = args[0]
80
- updates = args[1]
81
- options = args[2]
80
+ updates = args[1]
81
+ options = args[2]
82
82
  else
83
- split_args = args.partition{|a| a.is_a?(BSON::ObjectId)}
84
- criteria = {:id => split_args[0]}
85
- updates = split_args[1].first
86
- options = split_args[1].last
87
- end
83
+ criteria, (updates, options) = args.partition { |a| !a.is_a?(Hash) }
84
+ criteria = { :id => criteria }
85
+ end
86
+ upgrade_legacy_safe_usage!(options)
87
+
88
88
  [criteria_hash(criteria).to_hash, updates, options]
89
89
  end
90
+
91
+ def upgrade_legacy_safe_usage!(options)
92
+ if options and options.key?(:safe)
93
+ options.merge! Utils.get_safe_options(options)
94
+ options.delete :safe
95
+ end
96
+ end
90
97
  end
91
98
 
92
99
  def unset(*args)
93
- self.class.unset(id, *args)
100
+ self.class.unset({:_id => id}, *args)
94
101
  end
95
102
 
96
103
  def increment(hash, options=nil)
97
- self.class.increment(id, hash, options)
104
+ self.class.increment({:_id => id}, hash, options)
98
105
  end
99
106
 
100
107
  def decrement(hash, options=nil)
101
- self.class.decrement(id, hash, options)
108
+ self.class.decrement({:_id => id}, hash, options)
102
109
  end
103
110
 
104
111
  def set(hash, options=nil)
105
- self.class.set(id, hash, options)
112
+ self.class.set({:_id => id}, hash, options)
106
113
  end
107
114
 
108
115
  def push(hash, options=nil)
109
- self.class.push(id, hash, options)
116
+ self.class.push({:_id => id}, hash, options)
110
117
  end
111
118
 
112
119
  def push_all(hash, options=nil)
113
- self.class.push_all(id, hash, options)
120
+ self.class.push_all({:_id => id}, hash, options)
114
121
  end
115
122
 
116
123
  def pull(hash, options=nil)
117
- self.class.pull(id, hash, options)
124
+ self.class.pull({:_id => id}, hash, options)
118
125
  end
119
126
 
120
127
  def pull_all(hash, options=nil)
121
- self.class.pull_all(id, hash, options)
128
+ self.class.pull_all({:_id => id}, hash, options)
122
129
  end
123
130
 
124
131
  def add_to_set(hash, options=nil)
125
- self.class.push_uniq(id, hash, options)
132
+ self.class.push_uniq({:_id => id}, hash, options)
126
133
  end
127
134
  alias push_uniq add_to_set
128
135
 
129
136
  def pop(hash, options=nil)
130
- self.class.pop(id, hash, options)
137
+ self.class.pop({:_id => id}, hash, options)
131
138
  end
132
139
  end
133
140
  end
134
- end
141
+ end
@@ -5,9 +5,18 @@ module MongoMapper
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  module ClassMethods
8
+ def inherited(subclass)
9
+ unless subclass.embeddable?
10
+ subclass.connection(connection)
11
+ subclass.set_database_name(database_name)
12
+ subclass.set_collection_name(collection_name) unless subclass.explicit_collection_defined?
13
+ end
14
+ super
15
+ end
16
+
8
17
  def connection(mongo_connection=nil)
9
18
  assert_supported
10
- if mongo_connection.nil?
19
+ if mongo_connection.nil? && MongoMapper.connection?
11
20
  @connection ||= MongoMapper.connection
12
21
  else
13
22
  @connection = mongo_connection
@@ -22,7 +31,7 @@ module MongoMapper
22
31
 
23
32
  def database_name
24
33
  assert_supported
25
- @database_name
34
+ @database_name ||= nil # ||= idiom prevents uninitialized ivar warnings.
26
35
  end
27
36
 
28
37
  def database
@@ -51,8 +60,9 @@ module MongoMapper
51
60
 
52
61
  private
53
62
  def assert_supported
54
- if embeddable?
55
- raise NotSupported.new('This is not supported for embeddable documents at this time.')
63
+ @embeddable ||= embeddable?
64
+ if @embeddable
65
+ raise MongoMapper::NotSupported.new('This is not supported for embeddable documents at this time.')
56
66
  end
57
67
  end
58
68
  end
@@ -66,4 +76,4 @@ module MongoMapper
66
76
  end
67
77
  end
68
78
  end
69
- end
79
+ end
@@ -1,5 +1,5 @@
1
1
  # encoding: UTF-8
2
- require 'mongo_mapper/plugins/querying/decorator'
2
+ require 'mongo_mapper/plugins/querying/decorated_plucky_query'
3
3
 
4
4
  module MongoMapper
5
5
  module Plugins
@@ -24,11 +24,17 @@ module MongoMapper
24
24
  end
25
25
 
26
26
  def create(*docs)
27
- initialize_each(*docs) { |doc| doc.save }
27
+ initialize_each(*docs) do |doc|
28
+ yield doc if block_given?
29
+ doc.save
30
+ end
28
31
  end
29
32
 
30
33
  def create!(*docs)
31
- initialize_each(*docs) { |doc| doc.save! }
34
+ initialize_each(*docs) do |doc|
35
+ yield doc if block_given?
36
+ doc.save!
37
+ end
32
38
  end
33
39
 
34
40
  def update(*args)
@@ -40,31 +46,15 @@ module MongoMapper
40
46
  end
41
47
  end
42
48
 
43
- def delete(*ids)
44
- query(:_id => ids.flatten).remove
45
- end
46
-
47
- def delete_all(options={})
48
- query(options).remove
49
- end
50
-
51
- def destroy(*ids)
52
- find_some!(ids.flatten).each { |doc| doc.destroy }
53
- end
54
-
55
- def destroy_all(options={})
56
- find_each(options) { |document| document.destroy }
57
- end
58
-
59
49
  # @api private for now
60
50
  def query(options={})
61
- query = Plucky::Query.new(collection, :transformer => transformer)
62
- query.extend(Decorator)
51
+ query = MongoMapper::Plugins::Querying::DecoratedPluckyQuery.new(collection, :transformer => transformer)
63
52
  query.object_ids(object_id_keys)
64
53
  query.amend(options)
65
54
  query.model(self)
66
55
  query
67
56
  end
57
+ alias_method :scoped, :query
68
58
 
69
59
  # @api private for now
70
60
  def criteria_hash(criteria={})
@@ -76,22 +66,6 @@ module MongoMapper
76
66
  @transformer ||= lambda { |doc| load(doc) }
77
67
  end
78
68
 
79
- def find_some(ids, options={})
80
- query = query(options).amend(:_id => ids.flatten.compact.uniq)
81
- query.all
82
- end
83
-
84
- def find_some!(ids, options={})
85
- ids = ids.flatten.compact.uniq
86
- docs = find_some(ids, options)
87
-
88
- if ids.size != docs.size
89
- raise DocumentNotFound, "Couldn't find all of the ids (#{ids.to_sentence}). Found #{docs.size}, but was expecting #{ids.size}"
90
- end
91
-
92
- docs
93
- end
94
-
95
69
  def initialize_each(*docs)
96
70
  instances = []
97
71
  docs = [{}] if docs.blank?
@@ -149,16 +123,17 @@ module MongoMapper
149
123
  end
150
124
 
151
125
  def create(options={})
152
- save_to_collection(options)
126
+ save_to_collection(options.merge(:persistence_method => :insert))
153
127
  end
154
128
 
155
129
  def update(options={})
156
- save_to_collection(options)
130
+ save_to_collection(options.merge(:persistence_method => :save))
157
131
  end
158
132
 
159
133
  def save_to_collection(options={})
160
134
  @_new = false
161
- collection.save(to_mongo, :safe => options[:safe])
135
+ method = options.delete(:persistence_method) || :save
136
+ collection.send(method, to_mongo, Utils.get_safe_options(options))
162
137
  end
163
138
  end
164
139
  end
@@ -2,11 +2,27 @@
2
2
  module MongoMapper
3
3
  module Plugins
4
4
  module Querying
5
- Methods = Plucky::Methods + [:find!]
5
+ Methods = Plucky::Methods + [:delete, :delete_all, :destroy, :destroy_all, :find!]
6
6
 
7
- module Decorator
7
+ class DecoratedPluckyQuery < ::Plucky::Query
8
8
  include DynamicQuerying::ClassMethods
9
9
 
10
+ def delete(*ids)
11
+ where(:_id => ids.flatten).remove
12
+ end
13
+
14
+ def delete_all(options = {})
15
+ where(options).remove
16
+ end
17
+
18
+ def destroy(*ids)
19
+ [find!(*ids.flatten.compact.uniq)].flatten.each { |doc| doc.destroy }
20
+ end
21
+
22
+ def destroy_all(options={})
23
+ find_each(options) { |document| document.destroy }
24
+ end
25
+
10
26
  def model(model=nil)
11
27
  return @model if model.nil?
12
28
  @model = model
@@ -14,6 +30,7 @@ module MongoMapper
14
30
  end
15
31
 
16
32
  def find!(*ids)
33
+ ids = Array(ids).flatten.uniq
17
34
  raise DocumentNotFound, "Couldn't find without an ID" if ids.size == 0
18
35
 
19
36
  find(*ids).tap do |result|
@@ -27,8 +44,11 @@ module MongoMapper
27
44
  def method_missing(method, *args, &block)
28
45
  return super unless model.respond_to?(method)
29
46
  result = model.send(method, *args, &block)
30
- return super unless result.is_a?(Plucky::Query)
31
- merge(result)
47
+ if result.is_a?(Plucky::Query)
48
+ merge(result)
49
+ else
50
+ result
51
+ end
32
52
  end
33
53
  end
34
54
  end
@@ -26,13 +26,25 @@ module MongoMapper
26
26
  end
27
27
 
28
28
  def read_attribute_before_type_cast(name)
29
- read_key_before_type_cast(name)
29
+ @__mm_pre_cast ||= {}
30
+ name = unalias_key name
31
+ if !@__mm_pre_cast.key?(name)
32
+ @__mm_pre_cast[name] = read_attribute(name)
33
+ end
34
+ @__mm_pre_cast[name]
30
35
  end
31
36
 
32
37
  def write_attribute(name, value)
33
38
  self[name] = value
34
39
  end
35
40
 
41
+ def write_key(name, value)
42
+ name = unalias_key name
43
+ @__mm_pre_cast ||= {}
44
+ @__mm_pre_cast[name.to_s] = value
45
+ super
46
+ end
47
+
36
48
  module ClassMethods
37
49
  def has_one(*args)
38
50
  one(*args)
@@ -43,7 +55,7 @@ module MongoMapper
43
55
  end
44
56
 
45
57
  def column_names
46
- keys.keys
58
+ unaliased_keys.keys
47
59
  end
48
60
 
49
61
  # Returns returns an ActiveRecordAssociationAdapter for an association. This adapter has an API that is a
@@ -52,6 +64,14 @@ module MongoMapper
52
64
  def reflect_on_association(name)
53
65
  ActiveRecordAssociationAdapter.for_association(associations[name]) if associations[name]
54
66
  end
67
+
68
+ def create_accessors_for(key)
69
+ super do
70
+ define_method "#{key.name}_before_type_cast" do
71
+ read_attribute_before_type_cast key.name
72
+ end
73
+ end
74
+ end
55
75
  end
56
76
  end
57
77
  end
@@ -5,22 +5,25 @@ module MongoMapper
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  module ClassMethods
8
+ attr_reader :safe_options
9
+
8
10
  def inherited(subclass)
9
11
  super
10
- subclass.safe if safe?
12
+ subclass.safe(safe_options) if safe?
11
13
  end
12
14
 
13
- def safe
14
- @safe = true
15
+ def safe(options = true)
16
+ @safe_options = options
15
17
  end
16
18
 
17
19
  def safe?
18
- @safe == true
20
+ @safe_options ||= nil
21
+ !!@safe_options
19
22
  end
20
23
  end
21
24
 
22
25
  def save_to_collection(options={})
23
- options[:safe] = self.class.safe? unless options.key?(:safe)
26
+ options[:safe] = self.class.safe_options if !options.key?(:safe) && self.class.safe?
24
27
  super
25
28
  end
26
29
  end
@@ -11,10 +11,11 @@ module MongoMapper
11
11
  module ClassMethods
12
12
  def inherited(subclass)
13
13
  key :_type, String unless key?(:_type)
14
- subclass.instance_variable_set("@single_collection_inherited", true)
15
- subclass.set_collection_name(collection_name) unless subclass.embeddable?
16
- subclass.single_collection_parent = self
17
14
  super
15
+ if @collection_name == subclass.instance_variable_get("@collection_name")
16
+ subclass.single_collection_parent = self
17
+ subclass.instance_variable_set("@single_collection_inherited", true)
18
+ end
18
19
  end
19
20
 
20
21
  def single_collection_root
@@ -29,6 +30,27 @@ module MongoMapper
29
30
  root
30
31
  end
31
32
 
33
+ def criteria_hash(criteria={})
34
+ if single_collection_inherited?
35
+ super criteria.merge(:_type => name)
36
+ else
37
+ super
38
+ end
39
+ end
40
+
41
+ def set_collection_name(name)
42
+ if single_collection_inherited?
43
+ single_collection_parent = nil
44
+ @single_collection_inherited = false
45
+ end
46
+ @collection_defined = true
47
+ super
48
+ end
49
+
50
+ def explicit_collection_defined?
51
+ @collection_defined == true
52
+ end
53
+
32
54
  def single_collection_parent
33
55
  @single_collection_parent
34
56
  end
@@ -38,7 +60,7 @@ module MongoMapper
38
60
  end
39
61
 
40
62
  def single_collection_inherited?
41
- @single_collection_inherited == true
63
+ !!(@single_collection_inherited ||= false)
42
64
  end
43
65
 
44
66
  def query(options={})
@@ -10,18 +10,19 @@ module MongoMapper
10
10
 
11
11
  module ClassMethods
12
12
  def scope(name, scope_options={})
13
- scopes[name] = lambda do |*args|
13
+ # Assign to _scopes instead of using []= to avoid mixing subclass scopes
14
+ self._scopes = scopes.merge(name => lambda do |*args|
14
15
  result = scope_options.is_a?(Proc) ? scope_options.call(*args) : scope_options
15
16
  result = self.query(result) if result.is_a?(Hash)
16
17
  self.query.merge(result)
17
- end
18
+ end)
18
19
  singleton_class.send :define_method, name, &scopes[name]
19
20
  end
20
21
 
21
22
  def scopes
22
- self._scopes || self._scopes = {}
23
+ self._scopes ||= {}
23
24
  end
24
25
  end
25
26
  end
26
27
  end
27
- end
28
+ end