mongo_mapper 0.9.2 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/UPGRADES +6 -0
- data/lib/mongo_mapper.rb +1 -2
- data/lib/mongo_mapper/document.rb +0 -1
- data/lib/mongo_mapper/embedded_document.rb +0 -1
- data/lib/mongo_mapper/extensions/float.rb +1 -1
- data/lib/mongo_mapper/plugins.rb +2 -8
- data/lib/mongo_mapper/plugins/associations/belongs_to_association.rb +2 -0
- data/lib/mongo_mapper/plugins/associations/many_association.rb +4 -4
- data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +9 -1
- data/lib/mongo_mapper/plugins/associations/one_as_proxy.rb +22 -0
- data/lib/mongo_mapper/plugins/associations/one_association.rb +29 -1
- data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +0 -1
- data/lib/mongo_mapper/plugins/associations/one_proxy.rb +43 -16
- data/lib/mongo_mapper/plugins/clone.rb +1 -1
- data/lib/mongo_mapper/plugins/dirty.rb +6 -15
- data/lib/mongo_mapper/plugins/document.rb +5 -5
- data/lib/mongo_mapper/plugins/embedded_callbacks.rb +3 -3
- data/lib/mongo_mapper/plugins/keys.rb +0 -19
- data/lib/mongo_mapper/plugins/keys/key.rb +0 -4
- data/lib/mongo_mapper/railtie.rb +1 -2
- data/lib/mongo_mapper/version.rb +1 -1
- data/test/functional/associations/test_belongs_to_proxy.rb +15 -0
- data/test/functional/associations/test_many_documents_proxy.rb +161 -0
- data/test/functional/associations/test_one_as_proxy.rb +485 -0
- data/test/functional/associations/test_one_proxy.rb +188 -27
- data/test/functional/test_dirty.rb +9 -0
- data/test/functional/test_document.rb +5 -0
- data/test/support/railtie.rb +4 -0
- data/test/support/railtie/autoloaded.rb +2 -0
- data/test/support/railtie/not_autoloaded.rb +3 -0
- data/test/support/railtie/parent.rb +3 -0
- data/test/unit/associations/test_one_association.rb +18 -0
- data/test/unit/test_extensions.rb +4 -0
- data/test/unit/test_keys.rb +0 -22
- data/test/unit/test_plugins.rb +1 -46
- data/test/unit/test_railtie.rb +61 -0
- metadata +18 -14
- data/lib/mongo_mapper/support/descendant_appends.rb +0 -45
- data/test/functional/test_string_id_compatibility.rb +0 -75
- data/test/unit/test_descendant_appends.rb +0 -63
data/UPGRADES
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
0.9 => 0.10
|
2
|
+
* Using String IDs are no longer supported. If you are declaring your own ID, ensure it is an ObjectId, and set the default
|
3
|
+
key :_id, ObjectId, :default => lambda { BSON::ObjectId.new }
|
4
|
+
* The :dependent association option now applies to both when the parent is destroyed and when the association is reassigned (one and many associations)
|
5
|
+
* The default :dependent option is now :nullify for both when the parent is destroyed and when the association is reassigned
|
6
|
+
|
1
7
|
0.8.6 => 0.9
|
2
8
|
* [attribute]_before_typecast should become [attribute]_before_type_cast (note the extra _)
|
3
9
|
* Change validates_exclusion_of :within option to :in
|
data/lib/mongo_mapper.rb
CHANGED
@@ -72,6 +72,7 @@ module MongoMapper
|
|
72
72
|
autoload :ManyEmbeddedPolymorphicProxy, 'mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy'
|
73
73
|
autoload :ManyDocumentsAsProxy, 'mongo_mapper/plugins/associations/many_documents_as_proxy'
|
74
74
|
autoload :OneProxy, 'mongo_mapper/plugins/associations/one_proxy'
|
75
|
+
autoload :OneAsProxy, 'mongo_mapper/plugins/associations/one_as_proxy'
|
75
76
|
autoload :OneEmbeddedProxy, 'mongo_mapper/plugins/associations/one_embedded_proxy'
|
76
77
|
autoload :InArrayProxy, 'mongo_mapper/plugins/associations/in_array_proxy'
|
77
78
|
end
|
@@ -84,8 +85,6 @@ Dir[File.join(File.dirname(__FILE__), 'mongo_mapper', 'extensions', '*.rb')].eac
|
|
84
85
|
require extension
|
85
86
|
end
|
86
87
|
|
87
|
-
require 'mongo_mapper/support/descendant_appends'
|
88
|
-
|
89
88
|
# FIXME: autoload with proxy is failing, need to investigate
|
90
89
|
require 'mongo_mapper/plugins/associations/proxy'
|
91
90
|
|
data/lib/mongo_mapper/plugins.rb
CHANGED
@@ -8,14 +8,8 @@ module MongoMapper
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def plugin(mod)
|
11
|
-
|
12
|
-
|
13
|
-
else
|
14
|
-
warn "[DEPRECATED] Plugins must extend ActiveSupport::Concern"
|
15
|
-
extend mod::ClassMethods if mod.const_defined?(:ClassMethods)
|
16
|
-
include mod::InstanceMethods if mod.const_defined?(:InstanceMethods)
|
17
|
-
mod.configure(self) if mod.respond_to?(:configure)
|
18
|
-
end
|
11
|
+
raise ArgumentError, "Plugins must extend ActiveSupport::Concern" unless ActiveSupport::Concern === mod
|
12
|
+
include mod
|
19
13
|
direct_descendants.each {|model| model.send(:include, mod) }
|
20
14
|
plugins << mod
|
21
15
|
end
|
@@ -41,11 +41,11 @@ module MongoMapper
|
|
41
41
|
end
|
42
42
|
end_eval
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
options = self.options
|
44
|
+
association = self
|
45
|
+
options = self.options
|
47
46
|
|
48
|
-
|
47
|
+
model.before_destroy do
|
48
|
+
if !association.embeddable?
|
49
49
|
case options[:dependent]
|
50
50
|
when :destroy
|
51
51
|
self.get_proxy(association).destroy_all
|
@@ -8,7 +8,15 @@ module MongoMapper
|
|
8
8
|
|
9
9
|
def replace(docs)
|
10
10
|
load_target
|
11
|
-
|
11
|
+
|
12
|
+
(target - docs).each do |t|
|
13
|
+
case options[:dependent]
|
14
|
+
when :destroy then t.destroy
|
15
|
+
when :delete_all then t.delete
|
16
|
+
else t.update_attributes(self.foreign_key => nil)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
12
20
|
docs.each { |doc| prepare(doc).save }
|
13
21
|
reset
|
14
22
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
module MongoMapper
|
3
|
+
module Plugins
|
4
|
+
module Associations
|
5
|
+
class OneAsProxy < OneProxy
|
6
|
+
protected
|
7
|
+
def criteria
|
8
|
+
{type_key_name => proxy_owner.class.name, id_key_name => proxy_owner.id}
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
def type_key_name
|
13
|
+
"#{options[:as]}_type"
|
14
|
+
end
|
15
|
+
|
16
|
+
def id_key_name
|
17
|
+
"#{options[:as]}_id"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -8,7 +8,35 @@ module MongoMapper
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def proxy_class
|
11
|
-
@proxy_class ||=
|
11
|
+
@proxy_class ||=
|
12
|
+
if klass.embeddable?
|
13
|
+
OneEmbeddedProxy
|
14
|
+
elsif as?
|
15
|
+
OneAsProxy
|
16
|
+
else
|
17
|
+
OneProxy
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def setup(model)
|
22
|
+
super
|
23
|
+
|
24
|
+
association = self
|
25
|
+
options = self.options
|
26
|
+
|
27
|
+
model.before_destroy do
|
28
|
+
if !association.embeddable?
|
29
|
+
proxy = self.get_proxy(association)
|
30
|
+
|
31
|
+
unless proxy.nil?
|
32
|
+
case options[:dependent]
|
33
|
+
when :destroy then proxy.destroy
|
34
|
+
when :delete then proxy.delete
|
35
|
+
else proxy.nullify
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
12
40
|
end
|
13
41
|
|
14
42
|
def autosave?
|
@@ -19,38 +19,51 @@ module MongoMapper
|
|
19
19
|
load_target
|
20
20
|
|
21
21
|
if !target.nil? && target != doc
|
22
|
-
if
|
22
|
+
if target.persisted?
|
23
23
|
case options[:dependent]
|
24
|
-
when :delete
|
25
|
-
|
26
|
-
|
27
|
-
target
|
28
|
-
when :nullify
|
29
|
-
target[foreign_key] = nil
|
24
|
+
when :delete then target.delete
|
25
|
+
when :destroy then target.destroy
|
26
|
+
else
|
27
|
+
nullify_scope(target)
|
30
28
|
target.save
|
31
29
|
end
|
32
30
|
end
|
33
31
|
end
|
34
|
-
|
35
|
-
|
36
|
-
target.update_attributes(foreign_key => nil) unless target.nil?
|
37
|
-
else
|
32
|
+
|
33
|
+
unless doc.nil?
|
38
34
|
proxy_owner.save unless proxy_owner.persisted?
|
39
35
|
doc = klass.new(doc) unless doc.is_a?(klass)
|
40
|
-
doc
|
36
|
+
apply_scope(doc)
|
41
37
|
doc.save unless doc.persisted?
|
42
|
-
loaded
|
43
|
-
@target = doc
|
44
38
|
end
|
39
|
+
|
40
|
+
loaded
|
41
|
+
@target = doc
|
42
|
+
end
|
43
|
+
|
44
|
+
def destroy
|
45
|
+
target.destroy
|
46
|
+
reset
|
47
|
+
end
|
48
|
+
|
49
|
+
def delete
|
50
|
+
target.delete
|
51
|
+
reset
|
52
|
+
end
|
53
|
+
|
54
|
+
def nullify
|
55
|
+
nullify_scope(target)
|
56
|
+
target.save
|
57
|
+
reset
|
45
58
|
end
|
46
59
|
|
47
60
|
protected
|
48
61
|
def find_target
|
49
|
-
target_class.first(association.query_options.merge(
|
62
|
+
target_class.first(association.query_options.merge(criteria))
|
50
63
|
end
|
51
64
|
|
52
65
|
def instantiate_target(instantiator, attrs={})
|
53
|
-
@target = target_class.send(instantiator, attrs.update(
|
66
|
+
@target = target_class.send(instantiator, attrs.update(criteria))
|
54
67
|
loaded
|
55
68
|
@target
|
56
69
|
end
|
@@ -62,6 +75,20 @@ module MongoMapper
|
|
62
75
|
def foreign_key
|
63
76
|
options[:foreign_key] || proxy_owner.class.name.foreign_key
|
64
77
|
end
|
78
|
+
|
79
|
+
def criteria
|
80
|
+
{self.foreign_key => proxy_owner.id}
|
81
|
+
end
|
82
|
+
|
83
|
+
def nullify_scope(doc)
|
84
|
+
criteria.each { |key, value| doc[key] = nil }
|
85
|
+
doc
|
86
|
+
end
|
87
|
+
|
88
|
+
def apply_scope(doc)
|
89
|
+
criteria.each { |key, value| doc[key] = value }
|
90
|
+
doc
|
91
|
+
end
|
65
92
|
end
|
66
93
|
end
|
67
94
|
end
|
@@ -20,10 +20,6 @@ module MongoMapper
|
|
20
20
|
clear_changes { super }
|
21
21
|
end
|
22
22
|
|
23
|
-
def save!(*)
|
24
|
-
clear_changes { super }
|
25
|
-
end
|
26
|
-
|
27
23
|
def reload(*)
|
28
24
|
super.tap { clear_changes }
|
29
25
|
end
|
@@ -51,19 +47,14 @@ module MongoMapper
|
|
51
47
|
|
52
48
|
def write_key(key, value)
|
53
49
|
key = key.to_s
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
|
-
def attribute_should_change?(key, old, value)
|
61
|
-
attribute_changed?(key) == false && attribute_value_changed?(key, old, value)
|
50
|
+
attribute_will_change!(key) unless attribute_changed?(key)
|
51
|
+
super(key, value).tap do
|
52
|
+
changed_attributes.delete(key) unless attribute_value_changed?(key)
|
53
|
+
end
|
62
54
|
end
|
63
55
|
|
64
|
-
def attribute_value_changed?(key_name
|
65
|
-
|
66
|
-
old != value
|
56
|
+
def attribute_value_changed?(key_name)
|
57
|
+
attribute_was(key_name) != read_key(key_name)
|
67
58
|
end
|
68
59
|
end
|
69
60
|
end
|
@@ -21,12 +21,12 @@ module MongoMapper
|
|
21
21
|
|
22
22
|
def reload
|
23
23
|
if doc = collection.find_one(:_id => id)
|
24
|
-
|
25
|
-
|
26
|
-
get_proxy(association).reset
|
27
|
-
end
|
28
|
-
instance.attributes = doc
|
24
|
+
self.class.associations.each_value do |association|
|
25
|
+
get_proxy(association).reset
|
29
26
|
end
|
27
|
+
instance_variables.each { |ivar| instance_variable_set(ivar, nil) }
|
28
|
+
self.attributes = doc
|
29
|
+
self
|
30
30
|
else
|
31
31
|
raise DocumentNotFound, "Document match #{_id.inspect} does not exist in #{collection.name} collection"
|
32
32
|
end
|
@@ -11,7 +11,7 @@ module MongoMapper
|
|
11
11
|
end
|
12
12
|
|
13
13
|
module InstanceMethods
|
14
|
-
def run_callbacks(callback, &block)
|
14
|
+
def run_callbacks(callback, *args, &block)
|
15
15
|
embedded_docs = []
|
16
16
|
|
17
17
|
embedded_associations.each do |association|
|
@@ -20,12 +20,12 @@ module MongoMapper
|
|
20
20
|
|
21
21
|
block = embedded_docs.inject(block) do |chain, doc|
|
22
22
|
if doc.class.respond_to?("_#{callback}_callbacks")
|
23
|
-
lambda { doc.run_callbacks(callback, &chain) }
|
23
|
+
lambda { doc.run_callbacks(callback, *args, &chain) }
|
24
24
|
else
|
25
25
|
chain
|
26
26
|
end
|
27
27
|
end
|
28
|
-
super callback, &block
|
28
|
+
super callback, *args, &block
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -47,11 +47,6 @@ module MongoMapper
|
|
47
47
|
object_id_keys.include?(name.to_sym)
|
48
48
|
end
|
49
49
|
|
50
|
-
# API Private
|
51
|
-
def can_default_id?
|
52
|
-
keys['_id'].can_default_id?
|
53
|
-
end
|
54
|
-
|
55
50
|
def to_mongo(instance)
|
56
51
|
return nil if instance.nil?
|
57
52
|
instance.to_mongo
|
@@ -163,7 +158,6 @@ module MongoMapper
|
|
163
158
|
|
164
159
|
module InstanceMethods
|
165
160
|
def initialize(attrs={})
|
166
|
-
default_id_value(attrs)
|
167
161
|
@_new = true
|
168
162
|
assign(attrs)
|
169
163
|
end
|
@@ -171,7 +165,6 @@ module MongoMapper
|
|
171
165
|
def initialize_from_database(attrs={})
|
172
166
|
@_new = false
|
173
167
|
load_from_database(attrs)
|
174
|
-
default_id_value(attrs)
|
175
168
|
self
|
176
169
|
end
|
177
170
|
|
@@ -266,18 +259,6 @@ module MongoMapper
|
|
266
259
|
keys.values.select { |key| key.embeddable? }
|
267
260
|
end
|
268
261
|
|
269
|
-
def default_id_value(attrs={})
|
270
|
-
id_provided = !attrs.nil? && attrs.keys.map { |k| k.to_s }.detect { |k| k == 'id' || k == '_id' }
|
271
|
-
if !id_provided && self.class.can_default_id?
|
272
|
-
unless keys['_id'].default_value
|
273
|
-
warn "[DEPRECATED] Custom IDs will no longer be automatically populated. If you definte your own :_id key, set a default:\n key :_id, String, :default => lambda { BSON::ObjectId.new }"
|
274
|
-
warn caller.grep(/test/).join("\n")
|
275
|
-
end
|
276
|
-
|
277
|
-
write_key :_id, BSON::ObjectId.new
|
278
|
-
end
|
279
|
-
end
|
280
|
-
|
281
262
|
private
|
282
263
|
def load_from_database(attrs)
|
283
264
|
return if attrs.blank?
|
data/lib/mongo_mapper/railtie.rb
CHANGED
@@ -37,10 +37,9 @@ module MongoMapper
|
|
37
37
|
initializer "mongo_mapper.prepare_dispatcher" do |app|
|
38
38
|
# See http://groups.google.com/group/mongomapper/browse_thread/thread/68f62e8eda43b43a/4841dba76938290c
|
39
39
|
# to_prepare is called before each request in development mode and the first request in production.
|
40
|
+
|
40
41
|
ActionDispatch::Callbacks.to_prepare do
|
41
42
|
unless app.config.cache_classes
|
42
|
-
# Rails reloading was making descendants fill up and leak memory, these make sure they get cleared
|
43
|
-
ActiveSupport::DescendantsTracker.clear
|
44
43
|
MongoMapper::Plugins::IdentityMap.models.clear
|
45
44
|
end
|
46
45
|
end
|
data/lib/mongo_mapper/version.rb
CHANGED
@@ -102,6 +102,21 @@ class BelongsToProxyTest < Test::Unit::TestCase
|
|
102
102
|
@comment_class.new(:name => 'Foo', :post_id => id).post.nil?.should be_true
|
103
103
|
end
|
104
104
|
|
105
|
+
should "define foreign key if it doesn't exist" do
|
106
|
+
@category_class = Doc()
|
107
|
+
@post_class.belongs_to :category, :class => @category_class
|
108
|
+
|
109
|
+
@post_class.key?(:category_id).should be_true
|
110
|
+
end
|
111
|
+
|
112
|
+
should "not define foreign key if it already exists" do
|
113
|
+
@category_class = Doc()
|
114
|
+
@post_class.key :category_id, String
|
115
|
+
@post_class.belongs_to :category, :class => @category_class
|
116
|
+
|
117
|
+
@post_class.keys['category_id'].type.should == String
|
118
|
+
end
|
119
|
+
|
105
120
|
context ":dependent" do
|
106
121
|
setup do
|
107
122
|
# FIXME: make use of already defined models
|