Demetrius Nunes
2005-Jan-10 01:40 UTC
Principle of Least Surprise broken in AR new finders?
I started using the new AR dynamic finders and there is a behavior that doesn''t seem quite right: The normal #find method raises an exception when it doesn''t find a record. (I''d prefer if it only returned nil, but that''s ok.) The dynamic #find_by_something (not the #find_all_by) doesn''t raise an exception when it doesn''t return a record, only a empty array. I guess the dynamic finder should behave like the static #find, is that correct? DHH, can I work on a patch for this? Rgds, Dema
David Heinemeier Hansson
2005-Jan-10 02:28 UTC
Re: Principle of Least Surprise broken in AR new finders?
> I guess the dynamic finder should behave like the static #find, is > that correct? DHH, can I work on a patch for this?The logical correspondent to the dynamic finders are actually not Base#find, but rather Base#find_first, which does return nil. So it seems natural that the dynamic finders do the same. It also makes stuff like the following possible: if user = User.find_by_user_name_and_password(user_name, password) # you''re logged in -- David Heinemeier Hansson, http://www.basecamphq.com/ -- Web-based Project Management http://www.rubyonrails.org/ -- Web-application framework for Ruby http://macromates.com/ -- TextMate: Code and markup editor (OS X) http://www.loudthinking.com/ -- Broadcasting Brain
Marcel Molina Jr.
2005-Jan-10 06:20 UTC
Re: Principle of Least Surprise broken in AR new finders?
On Mon, Jan 10, 2005 at 03:33:15AM -0300, Demetrius Nunes wrote:> David Heinemeier Hansson wrote: > > >The logical correspondent to the dynamic finders are actually not > >Base#find, but rather Base#find_first, which does return nil. So it > >seems natural that the dynamic finders do the same. It also makes > >stuff like the following possible: > > > >if user = User.find_by_user_name_and_password(user_name, password) > > # you''re logged in > >-- > > David, what is the reason for Base#find raising an exception? Wouldnt it > be better if it just return nil on a no-find? That would allow the same > kind of code you wrote above. Or maybe, is it because you''re saying: "if > you are trying to find a row by its ''id'' then it better be right, > or...". Is that it? > > Anyway, in many concurrent situations a correct ''id'' maybe passed > against Base#find but some other user has just deleted id, so it would > be nicer to write: > > if user = User.find(id) > ... > > than > > begin > user = User.find(id) > ... > rescue > ... > end > > Or am I completely out of track here?I can quote an answer DHH has given for this: Because #find is going for a specific, known record If that record wasn''t available, that''s an exceptional state Unlike find_all that works like a search One can do @lala = Lala.find(id_does_not_exist) rescue nil marcel -- Marcel Molina Jr. <marcel-WRrfy3IlpWYdnm+yROfE0A@public.gmane.org>
Demetrius Nunes
2005-Jan-10 06:33 UTC
Re: Principle of Least Surprise broken in AR new finders?
David Heinemeier Hansson wrote:> The logical correspondent to the dynamic finders are actually not > Base#find, but rather Base#find_first, which does return nil. So it > seems natural that the dynamic finders do the same. It also makes > stuff like the following possible: > > if user = User.find_by_user_name_and_password(user_name, password) > # you''re logged in > --David, what is the reason for Base#find raising an exception? Wouldnt it be better if it just return nil on a no-find? That would allow the same kind of code you wrote above. Or maybe, is it because you''re saying: "if you are trying to find a row by its ''id'' then it better be right, or...". Is that it? Anyway, in many concurrent situations a correct ''id'' maybe passed against Base#find but some other user has just deleted id, so it would be nicer to write: if user = User.find(id) ... than begin user = User.find(id) ... rescue ... end Or am I completely out of track here? Rgds
Hi Demetrius. In the Java world (more accurately in the Enterprise Java EJB world) you get the same behaviour for findByPrimaryKey(...) vs findBySomeCriteria(...). This bugged me for ages until I realised that the logic goes like this: findByPrimaryKey(...) (or just plain find in railspeek) is looking for exactly one match. Zero or several matches is an error, so it fails fast with an exception, which is a Good Thing. findBySomeCriteria(...) is looking for zero or more matches, which can be completely covered by returning a list with zero or more entries. The purpose is not to have to use null check boilerplate code all over the place. You can iterate over a zero length list zero times and it will Just Work (TM). If you are looking for a record that might not be there, you could use a finder method that returns a list, so that the list could have zero or one entries in it. hth, Dan Demetrius Nunes wrote:> David Heinemeier Hansson wrote: > >> The logical correspondent to the dynamic finders are actually not >> Base#find, but rather Base#find_first, which does return nil. So it >> seems natural that the dynamic finders do the same. It also makes >> stuff like the following possible: >> >> if user = User.find_by_user_name_and_password(user_name, password) >> # you''re logged in >> -- > > > David, what is the reason for Base#find raising an exception? Wouldnt > it be better if it just return nil on a no-find? That would allow the > same kind of code you wrote above. Or maybe, is it because you''re > saying: "if you are trying to find a row by its ''id'' then it better be > right, or...". Is that it? > > Anyway, in many concurrent situations a correct ''id'' maybe passed > against Base#find but some other user has just deleted id, so it would > be nicer to write: > > if user = User.find(id) > ... > > than > > begin > user = User.find(id) > ... > rescue > ... > end > > Or am I completely out of track here? > > Rgds > _______________________________________________ > Rails mailing list > Rails-1W37MKcQCpIf0INCOvqR/iCwEArCW2h5@public.gmane.org > http://lists.rubyonrails.org/mailman/listinfo/rails
Tobias Luetke
2005-Jan-10 16:29 UTC
Re: Principle of Least Surprise broken in AR new finders?
> if user = User.find(id) > ... > > than > > begin > user = User.find(id) > ... > rescue > ... > end >I can offer: user = User.find(id) rescue nil -- Tobi http://www.hieraki.org - Open source book authoring http://blog.leetsoft.com - Technical weblog
Demetrius Nunes
2005-Jan-10 18:14 UTC
Re: Principle of Least Surprise broken in AR new finders?
Tobias Luetke wrote:>I can offer: > >user = User.find(id) rescue nil > > > >Thanks Tobi. Marcel Molina has pointed out the same solution already. Again, I gotta get more fluent on Ruby Slang. ;-)
Joe Van Dyk
2005-Jan-10 19:30 UTC
Re: Principle of Least Surprise broken in AR new finders?
On Mon, 10 Jan 2005 03:28:25 +0100, David Heinemeier Hansson <david-OiTZALl8rpK0mm7Ywyx6yg@public.gmane.org> wrote:> > I guess the dynamic finder should behave like the static #find, is > > that correct? DHH, can I work on a patch for this? > > The logical correspondent to the dynamic finders are actually not > Base#find, but rather Base#find_first, which does return nil. So it > seems natural that the dynamic finders do the same. It also makes stuff > like the following possible: > > if user = User.find_by_user_name_and_password(user_name, password) > # you''re logged inAre these dynamic finder methods documented anywhere?
David Heinemeier Hansson
2005-Jan-10 21:14 UTC
Re: Principle of Least Surprise broken in AR new finders?
> Are these dynamic finder methods documented anywhere?http://ar.rubyonrails.com/classes/ActiveRecord/Base.html under Dynamic attribute-based finders. -- David Heinemeier Hansson, http://www.basecamphq.com/ -- Web-based Project Management http://www.rubyonrails.org/ -- Web-application framework for Ruby http://macromates.com/ -- TextMate: Code and markup editor (OS X) http://www.loudthinking.com/ -- Broadcasting Brain