mongo_mapper 0.10.1 → 0.11.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 (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