Permalink
Browse files

Merge branch 'master' of git://github.com/collectiveidea/mongomapper

* 'master' of git://github.com/collectiveidea/mongomapper:
  Add an :autosave association option, defaulting to true for "many" and embedded "one" associations to remain consistent with current behavior.
  Add an :autosave option for belongs_to associations.
  Add build_*, create_* and create_*! methods to belongs_to associations.
  • Loading branch information...
2 parents ae94307 + 7cf80d8 commit 62146a3b2566824e4a721275f71f256c7ebfb1ce @bkeepers bkeepers committed Mar 8, 2011
@@ -83,7 +83,7 @@ def save_to_collection(options={})
super if defined?(super)
associations.each do |association_name, association|
proxy = get_proxy(association)
- proxy.save_to_collection(options) if proxy.proxy_respond_to?(:save_to_collection)
+ proxy.save_to_collection(options) if proxy.proxy_respond_to?(:save_to_collection) && association.autosave?
end
end
end
@@ -6,7 +6,7 @@ class Base
attr_reader :name, :options, :query_options
# Options that should not be considered MongoDB query options/criteria
- AssociationOptions = [:as, :class, :class_name, :dependent, :extend, :foreign_key, :in, :polymorphic]
+ AssociationOptions = [:as, :class, :class_name, :dependent, :extend, :foreign_key, :in, :polymorphic, :autosave]
def initialize(name, options={}, &extension)
@name, @options, @query_options, @original_options = name, {}, {}, options
@@ -62,6 +62,10 @@ def proxy_class
def setup(model)
end
+ def autosave?
+ raise NotImplementedError
+ end
+
private
def separate_options_and_conditions
@original_options.each_pair do |key, value|
@@ -34,8 +34,24 @@ def #{name}=(value)
def #{name}?
get_proxy(associations[#{name.inspect}]).present?
end
+
+ def build_#{name}(attrs={})
+ get_proxy(associations[#{name.inspect}]).build(attrs)
+ end
+
+ def create_#{name}(attrs={})
+ get_proxy(associations[#{name.inspect}]).create(attrs)
+ end
+
+ def create_#{name}!(attrs={})
+ get_proxy(associations[#{name.inspect}]).create!(attrs)
+ end
end_eval
end
+
+ def autosave?
+ options.fetch(:autosave, false)
+ end
end
end
end
@@ -18,11 +18,34 @@ def replace(doc)
@target
end
+ def build(attrs={})
+ instantiate_target(:new, attrs)
+ end
+
+ def create(attrs={})
+ instantiate_target(:create, attrs)
+ end
+
+ def create!(attrs={})
+ instantiate_target(:create!, attrs)
+ end
+
+ def save_to_collection(options={})
+ @target.save(options) if @target
+ end
+
protected
def find_target
return nil if proxy_owner[association.foreign_key].nil?
klass.find_by_id(proxy_owner[association.foreign_key])
end
+
+ def instantiate_target(instantiator, attrs={})
+ @target = klass.send(instantiator, attrs)
+ proxy_owner[association.foreign_key] = @target.id
+ loaded
+ @target
+ end
end
end
end
@@ -58,6 +58,9 @@ def #{name}=(value)
end
end
+ def autosave?
+ options.fetch(:autosave, true)
+ end
end
end
end
@@ -11,24 +11,9 @@ def proxy_class
@proxy_class ||= klass.embeddable? ? OneEmbeddedProxy : OneProxy
end
- def setup(model)
- super(model)
-
- model.associations_module.module_eval <<-end_eval
- def build_#{name}(attrs={})
- get_proxy(associations[#{name.inspect}]).build(attrs)
- end
-
- def create_#{name}(attrs={})
- get_proxy(associations[#{name.inspect}]).create(attrs)
- end
-
- def create_#{name}!(attrs={})
- get_proxy(associations[#{name.inspect}]).create!(attrs)
- end
- end_eval
+ def autosave?
+ options.fetch(:autosave, embeddable?)
end
-
end
end
end
@@ -5,7 +5,7 @@ class BelongsToProxyTest < Test::Unit::TestCase
def setup
@post_class = Doc()
@comment_class = Doc do
- key :post_id, String
+ key :post_id, ObjectId
end
@comment_class.belongs_to :post, :class => @post_class
@@ -133,4 +133,80 @@ class ::Thing
end
end
end
+
+ should "be able to build" do
+ @comment_class.belongs_to :post, :class => @post_class
+
+ comment = @comment_class.create
+ post = comment.build_post(:title => 'Hello, world!')
+ comment.post.should be_instance_of(@post_class)
+ comment.post.should be_new
+ comment.post.title.should == 'Hello, world!'
+ comment.post.should == post
+ comment.post_id.should == post.id
+ end
+
+ should "be able to create" do
+ @comment_class.belongs_to :post, :class => @post_class
+
+ comment = @comment_class.create
+ post = comment.create_post(:title => 'Hello, world!')
+ comment.post.should be_instance_of(@post_class)
+ comment.post.should_not be_new
+ comment.post.title.should == 'Hello, world!'
+ comment.post.should == post
+ comment.post_id.should == post.id
+ end
+
+ context "#create!" do
+ setup do
+ @post_class.key :title, String, :required => true
+ @comment_class.belongs_to :post, :class => @post_class
+ end
+
+ should "raise exception if invalid" do
+ comment = @comment_class.create
+ assert_raises(MongoMapper::DocumentNotValid) do
+ comment.create_post!
+ end
+ end
+
+ should "work if valid" do
+ comment = @comment_class.create
+ post = comment.create_post!(:title => 'Hello, world!')
+ comment.post.should be_instance_of(@post_class)
+ comment.post.should_not be_new
+ comment.post.title.should == 'Hello, world!'
+ comment.post.should == post
+ comment.post_id.should == post.id
+ end
+ end
+
+ context 'autosave' do
+ should 'not be true by default' do
+ @comment_class.associations[:post].options[:autosave].should_not be_true
+ end
+
+ should 'save parent changes when true' do
+ @comment_class.associations[:post].options[:autosave] = true
+
+ comment = @comment_class.create
+ post = comment.create_post(:title => 'Hello, world!')
+
+ comment.post.attributes = {:title => 'Hi, world.'}
+ comment.save
+
+ post.reload.title.should == 'Hi, world.'
+ end
+
+ should 'not save parent changes when false' do
+ comment = @comment_class.create
+ post = comment.create_post(:title => 'Hello, world!')
+
+ comment.post.attributes = {:title => 'Hi, world.'}
+ comment.save
+
+ post.reload.title.should == 'Hello, world!'
+ end
+ end
end

0 comments on commit 62146a3

Please sign in to comment.