osmbergs
osmbergs

Reputation: 1593

Odd behaviour when saving instances in Ruby DataMapper

having just started to look at DataMapper for Ruby ORM I've run into an issue that confuses me to no end.

The default behaviour when saving instances in DataMapper (through DataMapper::Resource.save) is, as far as I understand, to silently fail, return false from the save method and collect any errors in the errors collection. So far so good, this works as expected. The issue I see is with natural primary keys, where setting duplicate ones will throw an exception instead of silently returning false from the save method, blatantly disregarding the current setting of raise_on_save_failure. Consider the following snippet;

 require 'data_mapper'

class Thing
  include DataMapper::Resource
  property :name , String, :key=>  true
  property :description, String, length: 2..5
end

DataMapper.setup :default, "sqlite:memory"
DataMapper.finalize
DataMapper.auto_migrate!

#Create a thing and have it properly silently fail saving
t1=Thing.new(:name=>"n1",:description=>"verylongdescription" )

t1.save #ok
puts("t1 is saved:"+t1.saved?.to_s)
t1.errors.each do |e|
  puts e
end

#Create two things with the same key, and fail miserably in silently failing the second     save...
t1=Thing.new(:name=>"n1",:description=>"ok" )
t2=Thing.new(:name=>"n1",:description=>"ok" )

t1.save #ok
t2.save #not ok, raises Exception event though it shouldn't?

puts("t2 is saved:"+t1.saved?.to_s)
t2.errors.each do |e|
  puts e
end

The first save, on an instance failing a validation rule for the :description property behaves as expected. The third save, of an instance with duplicate keys, however does not, since it raises an execption instead of nicely just returning false.

Why is this? It is obviously possible to work around, but it doesn't feel very clear. Is the case that the silent behaviour will only apply to validation errors in the DataMapper layer, and any hard errors from the underlying datastore will be propagated as exceptions to the caller?

Thanks!

Upvotes: 1

Views: 435

Answers (1)

Adiel Mittmann
Adiel Mittmann

Reputation: 1764

As another user pointed out in a comment, this happens because setting raise_on_save_failure to false doesn't mean that no exceptions will occur. It will always return false (with no exceptions) when validation errors occur.

Database errors will blow up, as you noticed, in the form of an exception. Such errors could happen due to a large number of factors (the connection failed, no disk space), including mundane ones like a duplicate key. DataMapper can't know whether the object you're trying to save possesses a duplicate key, so it just validates it and sends to the database, where the error actually occurs.

Upvotes: 2

Related Questions