mongo_mapper 0.10.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/UPGRADES +3 -0
  2. data/examples/plugins.rb +2 -5
  3. data/lib/mongo_mapper.rb +1 -0
  4. data/lib/mongo_mapper/connection.rb +4 -0
  5. data/lib/mongo_mapper/embedded_document.rb +1 -0
  6. data/lib/mongo_mapper/extensions/object.rb +5 -6
  7. data/lib/mongo_mapper/plugins/accessible.rb +14 -16
  8. data/lib/mongo_mapper/plugins/associations.rb +21 -23
  9. data/lib/mongo_mapper/plugins/associations/base.rb +1 -1
  10. data/lib/mongo_mapper/plugins/associations/belongs_to_association.rb +4 -0
  11. data/lib/mongo_mapper/plugins/associations/many_association.rb +0 -4
  12. data/lib/mongo_mapper/plugins/associations/one_association.rb +1 -1
  13. data/lib/mongo_mapper/plugins/associations/one_embedded_polymorphic_proxy.rb +30 -0
  14. data/lib/mongo_mapper/plugins/caching.rb +11 -13
  15. data/lib/mongo_mapper/plugins/callbacks.rb +12 -14
  16. data/lib/mongo_mapper/plugins/clone.rb +11 -13
  17. data/lib/mongo_mapper/plugins/dirty.rb +36 -38
  18. data/lib/mongo_mapper/plugins/document.rb +20 -22
  19. data/lib/mongo_mapper/plugins/embedded_callbacks.rb +11 -13
  20. data/lib/mongo_mapper/plugins/embedded_document.rb +22 -24
  21. data/lib/mongo_mapper/plugins/equality.rb +6 -8
  22. data/lib/mongo_mapper/plugins/identity_map.rb +11 -13
  23. data/lib/mongo_mapper/plugins/inspect.rb +6 -8
  24. data/lib/mongo_mapper/plugins/keys.rb +109 -110
  25. data/lib/mongo_mapper/plugins/logger.rb +2 -4
  26. data/lib/mongo_mapper/plugins/modifiers.rb +32 -34
  27. data/lib/mongo_mapper/plugins/persistence.rb +5 -7
  28. data/lib/mongo_mapper/plugins/protected.rb +14 -16
  29. data/lib/mongo_mapper/plugins/querying.rb +29 -31
  30. data/lib/mongo_mapper/plugins/rails.rb +28 -22
  31. data/lib/mongo_mapper/plugins/rails/active_record_association_adapter.rb +33 -0
  32. data/lib/mongo_mapper/plugins/safe.rb +3 -5
  33. data/lib/mongo_mapper/plugins/sci.rb +3 -5
  34. data/lib/mongo_mapper/plugins/serialization.rb +49 -52
  35. data/lib/mongo_mapper/plugins/timestamps.rb +4 -6
  36. data/lib/mongo_mapper/plugins/validations.rb +8 -10
  37. data/lib/mongo_mapper/railtie/database.rake +1 -1
  38. data/lib/mongo_mapper/version.rb +1 -1
  39. data/lib/rails/generators/mongo_mapper/model/model_generator.rb +1 -1
  40. data/lib/rails/generators/mongo_mapper/model/templates/model.rb +2 -0
  41. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +63 -0
  42. data/test/functional/associations/test_one_embedded_polymorphic_proxy.rb +208 -0
  43. data/test/functional/test_accessible.rb +5 -0
  44. data/test/functional/test_embedded_document.rb +12 -0
  45. data/test/functional/test_modifiers.rb +19 -19
  46. data/test/functional/test_protected.rb +10 -0
  47. data/test/functional/test_querying.rb +15 -1
  48. data/test/functional/test_validations.rb +33 -0
  49. data/test/models.rb +14 -0
  50. data/test/unit/associations/test_one_association.rb +11 -0
  51. data/test/unit/test_mongo_mapper.rb +9 -0
  52. data/test/unit/test_plugins.rb +2 -4
  53. data/test/unit/test_rails_reflect_on_association.rb +118 -0
  54. metadata +15 -11
data/UPGRADES CHANGED
@@ -1,3 +1,6 @@
1
+ 0.10 => 0.11
2
+ * #update_attribute now ignores attr_accessible and attr_protected
3
+
1
4
  0.9 => 0.10
2
5
  * Using String IDs are no longer supported. If you are declaring your own ID, ensure it is an ObjectId, and set the default
3
6
  key :_id, ObjectId, :default => lambda { BSON::ObjectId.new }
@@ -16,11 +16,8 @@ module FooPlugin
16
16
  end
17
17
  end
18
18
 
19
- # InstanceMethods module will automatically get included
20
- module InstanceMethods
21
- def foo
22
- 'Foo instance method!'
23
- end
19
+ def foo
20
+ 'Foo instance method!'
24
21
  end
25
22
 
26
23
  # Any configuration can be done in the #included block, which gets
@@ -75,6 +75,7 @@ module MongoMapper
75
75
  autoload :OneProxy, 'mongo_mapper/plugins/associations/one_proxy'
76
76
  autoload :OneAsProxy, 'mongo_mapper/plugins/associations/one_as_proxy'
77
77
  autoload :OneEmbeddedProxy, 'mongo_mapper/plugins/associations/one_embedded_proxy'
78
+ autoload :OneEmbeddedPolymorphicProxy, 'mongo_mapper/plugins/associations/one_embedded_polymorphic_proxy'
78
79
  autoload :InArrayProxy, 'mongo_mapper/plugins/associations/in_array_proxy'
79
80
  end
80
81
  end
@@ -62,6 +62,10 @@ module MongoMapper
62
62
  raise 'Set config before connecting. MongoMapper.config = {...}' if config.blank?
63
63
  env = config_for_environment(environment)
64
64
 
65
+ if env['options'].is_a? Hash
66
+ options = env['options'].symbolize_keys.merge(options)
67
+ end
68
+
65
69
  MongoMapper.connection = if env['hosts']
66
70
  Mongo::ReplSetConnection.new( *env['hosts'].push(options) )
67
71
  else
@@ -19,6 +19,7 @@ module MongoMapper
19
19
  include Plugins::Rails
20
20
  include Plugins::Sci
21
21
  include Plugins::Serialization
22
+ include Plugins::Timestamps
22
23
  include Plugins::Validations
23
24
  include Plugins::EmbeddedCallbacks
24
25
 
@@ -2,6 +2,8 @@
2
2
  module MongoMapper
3
3
  module Extensions
4
4
  module Object
5
+ extend ActiveSupport::Concern
6
+
5
7
  module ClassMethods
6
8
  def to_mongo(value)
7
9
  value
@@ -12,16 +14,13 @@ module MongoMapper
12
14
  end
13
15
  end
14
16
 
15
- module InstanceMethods
16
- def to_mongo
17
- self.class.to_mongo(self)
18
- end
17
+ def to_mongo
18
+ self.class.to_mongo(self)
19
19
  end
20
20
  end
21
21
  end
22
22
  end
23
23
 
24
24
  class Object
25
- extend MongoMapper::Extensions::Object::ClassMethods
26
- include MongoMapper::Extensions::Object::InstanceMethods
25
+ include MongoMapper::Extensions::Object
27
26
  end
@@ -14,25 +14,23 @@ module MongoMapper
14
14
  end
15
15
  end
16
16
 
17
- module InstanceMethods
18
- def attributes=(attrs={})
19
- super(filter_inaccessible_attrs(attrs))
20
- end
21
-
22
- def update_attributes(attrs={})
23
- super(filter_inaccessible_attrs(attrs))
24
- end
17
+ def attributes=(attrs={})
18
+ super(filter_inaccessible_attrs(attrs))
19
+ end
25
20
 
26
- def update_attributes!(attrs={})
27
- super(filter_inaccessible_attrs(attrs))
28
- end
21
+ def update_attributes(attrs={})
22
+ super(filter_inaccessible_attrs(attrs))
23
+ end
29
24
 
30
- protected
31
- def filter_inaccessible_attrs(attrs)
32
- return attrs if !accessible_attributes? || attrs.blank?
33
- attrs.dup.delete_if { |key, val| !accessible_attributes.include?(key.to_sym) }
34
- end
25
+ def update_attributes!(attrs={})
26
+ super(filter_inaccessible_attrs(attrs))
35
27
  end
28
+
29
+ protected
30
+ def filter_inaccessible_attrs(attrs)
31
+ return attrs if !accessible_attributes? || attrs.blank?
32
+ attrs.dup.delete_if { |key, val| !accessible_attributes.include?(key.to_sym) }
33
+ end
36
34
  end
37
35
  end
38
36
  end
@@ -56,35 +56,33 @@ module MongoMapper
56
56
  end
57
57
  end
58
58
 
59
- module InstanceMethods
60
- def associations
61
- self.class.associations
62
- end
59
+ def associations
60
+ self.class.associations
61
+ end
63
62
 
64
- def embedded_associations
65
- associations.values.select { |assoc| assoc.embeddable? }
66
- end
63
+ def embedded_associations
64
+ associations.values.select { |assoc| assoc.embeddable? }
65
+ end
67
66
 
68
- def build_proxy(association)
69
- proxy = association.proxy_class.new(self, association)
70
- self.instance_variable_set(association.ivar, proxy)
67
+ def build_proxy(association)
68
+ proxy = association.proxy_class.new(self, association)
69
+ self.instance_variable_set(association.ivar, proxy)
71
70
 
72
- proxy
73
- end
71
+ proxy
72
+ end
74
73
 
75
- def get_proxy(association)
76
- unless proxy = self.instance_variable_get(association.ivar)
77
- proxy = build_proxy(association)
78
- end
79
- proxy
74
+ def get_proxy(association)
75
+ unless proxy = self.instance_variable_get(association.ivar)
76
+ proxy = build_proxy(association)
80
77
  end
78
+ proxy
79
+ end
81
80
 
82
- def save_to_collection(options={})
83
- super if defined?(super)
84
- associations.each do |association_name, association|
85
- proxy = get_proxy(association)
86
- proxy.save_to_collection(options) if proxy.proxy_respond_to?(:save_to_collection) && association.autosave?
87
- end
81
+ def save_to_collection(options={})
82
+ super if defined?(super)
83
+ associations.each do |association_name, association|
84
+ proxy = get_proxy(association)
85
+ proxy.save_to_collection(options) if proxy.proxy_respond_to?(:save_to_collection) && association.autosave?
88
86
  end
89
87
  end
90
88
  end
@@ -40,7 +40,7 @@ module MongoMapper
40
40
  end
41
41
 
42
42
  def type_key_name
43
- "#{as}_type"
43
+ "_type"
44
44
  end
45
45
 
46
46
  def as
@@ -3,6 +3,10 @@ module MongoMapper
3
3
  module Plugins
4
4
  module Associations
5
5
  class BelongsToAssociation < SingleAssociation
6
+ def type_key_name
7
+ "#{as}_type"
8
+ end
9
+
6
10
  def embeddable?
7
11
  false
8
12
  end
@@ -8,10 +8,6 @@ module MongoMapper
8
8
  @class_name ||= options[:class_name] || name.to_s.singularize.camelize
9
9
  end
10
10
 
11
- def type_key_name
12
- "_type"
13
- end
14
-
15
11
  # hate this, need to revisit
16
12
  def proxy_class
17
13
  @proxy_class ||= if klass.embeddable?
@@ -10,7 +10,7 @@ module MongoMapper
10
10
  def proxy_class
11
11
  @proxy_class ||=
12
12
  if klass.embeddable?
13
- OneEmbeddedProxy
13
+ polymorphic? ? OneEmbeddedPolymorphicProxy : OneEmbeddedProxy
14
14
  elsif as?
15
15
  OneAsProxy
16
16
  else
@@ -0,0 +1,30 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Associations
5
+ class OneEmbeddedPolymorphicProxy < OneEmbeddedProxy
6
+ def replace(value)
7
+ @value = value.respond_to?(:attributes) ? value.attributes.merge(association.type_key_name => value.class.name) : value
8
+ reset
9
+ end
10
+
11
+ protected
12
+ def find_target
13
+ if @value
14
+ child = polymorphic_class(@value).load(@value)
15
+ assign_references(child)
16
+ child
17
+ end
18
+ end
19
+
20
+ def polymorphic_class(doc)
21
+ if class_name = doc[association.type_key_name]
22
+ class_name.constantize
23
+ else
24
+ klass
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -4,19 +4,17 @@ module MongoMapper
4
4
  module Caching
5
5
  extend ActiveSupport::Concern
6
6
 
7
- module InstanceMethods
8
- def cache_key(*suffixes)
9
- cache_key = case
10
- when !persisted?
11
- "#{self.class.name}/new"
12
- when timestamp = self[:updated_at]
13
- "#{self.class.name}/#{id}-#{timestamp.to_s(:number)}"
14
- else
15
- "#{self.class.name}/#{id}"
16
- end
17
- cache_key += "/#{suffixes.join('/')}" unless suffixes.empty?
18
- cache_key
19
- end
7
+ def cache_key(*suffixes)
8
+ cache_key = case
9
+ when !persisted?
10
+ "#{self.class.name}/new"
11
+ when timestamp = self[:updated_at]
12
+ "#{self.class.name}/#{id}-#{timestamp.to_s(:number)}"
13
+ else
14
+ "#{self.class.name}/#{id}"
15
+ end
16
+ cache_key += "/#{suffixes.join('/')}" unless suffixes.empty?
17
+ cache_key
20
18
  end
21
19
  end
22
20
  end
@@ -4,23 +4,21 @@ module MongoMapper
4
4
  module Callbacks
5
5
  extend ActiveSupport::Concern
6
6
 
7
- module InstanceMethods
8
- def destroy
9
- run_callbacks(:destroy) { super }
10
- end
7
+ def destroy
8
+ run_callbacks(:destroy) { super }
9
+ end
11
10
 
12
- private
13
- def create_or_update(*)
14
- run_callbacks(:save) { super }
15
- end
11
+ private
12
+ def create_or_update(*)
13
+ run_callbacks(:save) { super }
14
+ end
16
15
 
17
- def create(*)
18
- run_callbacks(:create) { super }
19
- end
16
+ def create(*)
17
+ run_callbacks(:create) { super }
18
+ end
20
19
 
21
- def update(*)
22
- run_callbacks(:update) { super }
23
- end
20
+ def update(*)
21
+ run_callbacks(:update) { super }
24
22
  end
25
23
  end
26
24
  end
@@ -4,19 +4,17 @@ module MongoMapper
4
4
  module Clone
5
5
  extend ActiveSupport::Concern
6
6
 
7
- module InstanceMethods
8
- def initialize_copy(other)
9
- @_new = true
10
- @_destroyed = false
11
- @_id = nil
12
- associations.each do |name, association|
13
- instance_variable_set(association.ivar, nil)
14
- end
15
- self.attributes = other.attributes.clone.except(:_id).inject({}) do |hash, entry|
16
- key, value = entry
17
- hash[key] = value.duplicable? ? value.clone : value
18
- hash
19
- end
7
+ def initialize_copy(other)
8
+ @_new = true
9
+ @_destroyed = false
10
+ @_id = nil
11
+ associations.each do |name, association|
12
+ instance_variable_set(association.ivar, nil)
13
+ end
14
+ self.attributes = other.attributes.clone.except(:_id).inject({}) do |hash, entry|
15
+ key, value = entry
16
+ hash[key] = value.duplicable? ? value.clone : value
17
+ hash
20
18
  end
21
19
  end
22
20
  end
@@ -6,56 +6,54 @@ module MongoMapper
6
6
 
7
7
  include ::ActiveModel::Dirty
8
8
 
9
- module InstanceMethods
10
- def initialize(*)
11
- # never register initial id assignment as a change
12
- super.tap { changed_attributes.delete('_id') }
13
- end
9
+ def initialize(*)
10
+ # never register initial id assignment as a change
11
+ super.tap { changed_attributes.delete('_id') }
12
+ end
14
13
 
15
- def initialize_from_database(*)
16
- super.tap { changed_attributes.clear }
17
- end
14
+ def initialize_from_database(*)
15
+ super.tap { changed_attributes.clear }
16
+ end
18
17
 
19
- def save(*)
20
- clear_changes { super }
21
- end
18
+ def save(*)
19
+ clear_changes { super }
20
+ end
22
21
 
23
- def reload(*)
24
- super.tap { clear_changes }
25
- end
22
+ def reload(*)
23
+ super.tap { clear_changes }
24
+ end
26
25
 
27
- protected
26
+ protected
28
27
 
29
- def attribute_method?(attr)
30
- # This overrides ::ActiveSupport::Dirty#attribute_method? to allow attributes to be any key
31
- # in the attributes hash ( default ) or any key defined on the model that may not yet have
32
- # had a value stored in the attributes collection.
33
- super || key_names.include?(attr)
34
- end
28
+ def attribute_method?(attr)
29
+ # This overrides ::ActiveSupport::Dirty#attribute_method? to allow attributes to be any key
30
+ # in the attributes hash ( default ) or any key defined on the model that may not yet have
31
+ # had a value stored in the attributes collection.
32
+ super || key_names.include?(attr)
33
+ end
35
34
 
36
- def clear_changes
37
- previous = changes
38
- (block_given? ? yield : true).tap do |result|
39
- unless result == false #failed validation; nil is OK.
40
- @previously_changed = previous
41
- changed_attributes.clear
42
- end
35
+ def clear_changes
36
+ previous = changes
37
+ (block_given? ? yield : true).tap do |result|
38
+ unless result == false #failed validation; nil is OK.
39
+ @previously_changed = previous
40
+ changed_attributes.clear
43
41
  end
44
42
  end
43
+ end
45
44
 
46
- private
45
+ private
47
46
 
48
- def write_key(key, value)
49
- key = key.to_s
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
47
+ def write_key(key, value)
48
+ key = key.to_s
49
+ attribute_will_change!(key) unless attribute_changed?(key)
50
+ super(key, value).tap do
51
+ changed_attributes.delete(key) unless attribute_value_changed?(key)
54
52
  end
53
+ end
55
54
 
56
- def attribute_value_changed?(key_name)
57
- attribute_was(key_name) != read_key(key_name)
58
- end
55
+ def attribute_value_changed?(key_name)
56
+ attribute_was(key_name) != read_key(key_name)
59
57
  end
60
58
  end
61
59
  end
@@ -10,34 +10,32 @@ module MongoMapper
10
10
  end
11
11
  end
12
12
 
13
- module InstanceMethods
14
- def new?
15
- @_new
16
- end
13
+ def new?
14
+ @_new
15
+ end
17
16
 
18
- def destroyed?
19
- @_destroyed == true
20
- end
17
+ def destroyed?
18
+ @_destroyed == true
19
+ end
21
20
 
22
- def reload
23
- if doc = collection.find_one(:_id => id)
24
- self.class.associations.each_value do |association|
25
- get_proxy(association).reset
26
- end
27
- instance_variables.each { |ivar| instance_variable_set(ivar, nil) }
28
- load_from_database(doc)
29
- self
30
- else
31
- raise DocumentNotFound, "Document match #{_id.inspect} does not exist in #{collection.name} collection"
21
+ def reload
22
+ if doc = collection.find_one(:_id => id)
23
+ self.class.associations.each_value do |association|
24
+ get_proxy(association).reset
32
25
  end
33
- end
34
-
35
- # Used by embedded docs to find root easily without if/respond_to? stuff.
36
- # Documents are always root documents.
37
- def _root_document
26
+ instance_variables.each { |ivar| instance_variable_set(ivar, nil) }
27
+ load_from_database(doc)
38
28
  self
29
+ else
30
+ raise DocumentNotFound, "Document match #{_id.inspect} does not exist in #{collection.name} collection"
39
31
  end
40
32
  end
33
+
34
+ # Used by embedded docs to find root easily without if/respond_to? stuff.
35
+ # Documents are always root documents.
36
+ def _root_document
37
+ self
38
+ end
41
39
  end
42
40
  end
43
41
  end