#create/#save vs #create!/#save!

26 views
Skip to first unread message

Ashley Moran

unread,
Jun 29, 2009, 4:44:13 PM6/29/09
to DataMapper
Hi all

I'd just like to know what other people think of my interpretation of
#save/#save!.

Currently (0.9.x) the behaviour is:

#save: save, return true/false depending on success
#save!: save unvalidated; raise exception on persistence error

My reaction to this is that - ahem - banging the operation changes
*two* things about #save: it disables validations and it enables
propagation of persistence errors. To me, this makes the behaviour
surprising.

I think that having a #save method that catches all errors is
important - it means you can guarantee your app will not generated an
unexpected 500 error. In other words, I'm happy with the current #save.

In specs, having the examples fail fast is important. One of the two
main conventions of #<method>! is to raise errors (the other being to
modify the receiver). So I'm happy that #save! reraises persistence
errors.

BUT, #save! also disables validations. This means that in a spec, you
might create an invalid object that saves with #save!, but save
silently fails.

To me, these are two dimensions of one problem and need separating,
possibly with methods like this:

#save
#save!
#save_without_validations
#save_without_validations!

WDYAT?

Cheers
Ashley

--
http://www.patchspace.co.uk/
http://www.linkedin.com/in/ashleymoran
http://aviewfromafar.net/
http://twitter.com/ashleymoran


Dan Kubb (dkubb)

unread,
Jun 30, 2009, 1:48:27 AM6/30/09
to DataMapper
Hi Ashley,

> I'd just like to know what other people think of my interpretation of  
> #save/#save!.

The intention with the 0.10 behavior is:

#save - save the resource with hooks applied
#save! - save the resource without any hooks applied

Also #create, #destroy, #update all should conform to this behavior
across Resource, Collection and Model.

> One of the two  
> main conventions of #<method>! is to raise errors (the other being to  
> modify the receiver).  So I'm happy that #save! reraises persistence  
> errors.

I think the bang/non-bang convention you mention is actually Rails
specific. With DM we're trying to design according to the following
interpretation of their usage:

http://dablog.rubypal.com/2007/8/15/bang-methods-or-danger-will-rubyist

So the non-bang version is considered safe, and the bang is unsafe.
The bang method bypasses checks, and any tests that may have been
installed by plugins (like dm-constraints and dm-validations) and just
goes straight to the datastore and modifies the data directly.

> I think that having a #save method that catches all errors is
> important - it means you can guarantee your app will not generated an
> unexpected 500 error. In other words, I'm happy with the current #save.

Actually in most cases we don't attempt to catch datastore
exceptions. We just let them bubble them up. It might look like we
catch all errors, but that's not us, that's you using dm-validations
and dm-constraints. Those libs act as a gate keeper in front of the
datastore, short circuiting alot of things that wouldn't work before
the datastore even sees them. By the time a datastore exception
happens it's usually too late for DM to recover in a sane consistent
manner anyway, so I would only consider catching those exceptions if I
was to add more debug info, and then rethrow the exception up the
stack.

--

Dan
(dkubb)

Ashley Moran

unread,
Jul 6, 2009, 5:19:50 PM7/6/09
to datam...@googlegroups.com

On 30 Jun 2009, at 06:48, Dan Kubb (dkubb) wrote:

> The intention with the 0.10 behavior is:
>
> #save - save the resource with hooks applied
> #save! - save the resource without any hooks applied
>
> Also #create, #destroy, #update all should conform to this behavior
> across Resource, Collection and Model.

I did not know about the convention beforehand. Can you explain what
the thinking behind the saving without hooks is? (Sorry for the dumb
question - it may be an application of the convention you explain
below.)


>> One of the two
>> main conventions of #<method>! is to raise errors (the other being to
>> modify the receiver). So I'm happy that #save! reraises persistence
>> errors.
>
> I think the bang/non-bang convention you mention is actually Rails
> specific. With DM we're trying to design according to the following
> interpretation of their usage:
>
> http://dablog.rubypal.com/2007/8/15/bang-methods-or-danger-will-rubyist
>
> So the non-bang version is considered safe, and the bang is unsafe.
> The bang method bypasses checks, and any tests that may have been
> installed by plugins (like dm-constraints and dm-validations) and just
> goes straight to the datastore and modifies the data directly.

Yes, that's a better convention than the one I understood.


>> I think that having a #save method that catches all errors is
>> important - it means you can guarantee your app will not generated an
>> unexpected 500 error. In other words, I'm happy with the current
>> #save.
>
> Actually in most cases we don't attempt to catch datastore
> exceptions. We just let them bubble them up. It might look like we
> catch all errors, but that's not us, that's you using dm-validations
> and dm-constraints. Those libs act as a gate keeper in front of the
> datastore, short circuiting alot of things that wouldn't work before
> the datastore even sees them. By the time a datastore exception
> happens it's usually too late for DM to recover in a sane consistent
> manner anyway, so I would only consider catching those exceptions if I
> was to add more debug info, and then rethrow the exception up the
> stack.

Thanks for the explanation. The only problem I can see, is that
datastore exceptions are datastore-specific, and therefore break the
abstraction that DataMapper makes over persistence mechanisms? Is
this correct thinking, or is there another perspective?

Thanks

Reply all
Reply to author
Forward
0 new messages