Best way to find a single record using ActiveRecord 3 / Arel?
Asked Answered
Z

5

43

Where I used to do this:

Foo.find_by_bar('a-value')

I can now do this:

Foo.where(:bar => 'a-value').limit(1).first

Is this recommended? Is this the best way? Should I continue to use the "old" way because it continues to be useful syntactic sugar, or is there an Even Better way I can do that now, which will support chaining and all the other good stuff?

Zitvaa answered 13/6, 2011 at 3:38 Comment(3)
I actually quite like the old find_by_*. The intent is clear, and if that's all you need, the syntax is simpler.Stanfill
And its still perfectly valid in Rails 3. If using Rails 4, you can use find_by(bar: 'a-value').Nidorf
I came here looking for just a single record. If anyone else is after the same, I've popped an answer to this scenario down here :)Hayfield
P
52

Rails 4 :

Foo.find_by( bar: 'a_value', wibble: 'a wibble value' )
Peeress answered 10/2, 2014 at 5:14 Comment(3)
Can you add a source for this?Gatewood
Any idea why RubyMine warns that this method should not be called from view helper?Kerch
find_by is kind of a heavy operation and its advisable not to trigger while rendering viewPeeress
Q
26

I think the preferable way to return a single record would be along the lines of your second example, but you can omit the limit part:

Foo.where(:bar => 'a-value').first

This follows the new syntax and supports chaining if you want to add more conditions to the lookup.

Quartersaw answered 13/6, 2011 at 3:49 Comment(2)
Use Foo.where(:bar => 'a-value').first! if you want to ensure a record is found. That way ActiveRecord::RecordNotFound will be raised otherwise.Charest
Rails adds ORDER BY "foo"."id" ASC in this case. It can make the query less efficient.Selfgoverned
H
7

If you need one and only one record (which I came here looking for), Rails 7.0 introduces find_sole_by (or where(...).sole) for this.

The behaviour is as follows:

Finds the sole matching record. Raises ActiveRecord::RecordNotFound if no record is found. Raises ActiveRecord::SoleRecordExceeded if more than one record is found.

Use case is simple:

Foo.find_sole_by(bar: 'a-value')

Handy for those occasions where a single record is mandatory.

Hayfield answered 12/3, 2021 at 12:47 Comment(0)
S
5

Rails gives you a whole load of magic methods for this kind of thing:

Foo.find_by_bar('a-value')

You can also use multiple attributes:

Foo.find_by_bar_and_wibble('a foo value', 'a wibble value')

And appending a ! causes it to throw a RecordNotFound if nothing's found:

Foo.find_by_bar!('a-value')
Seismic answered 2/8, 2013 at 14:52 Comment(1)
These dynamic finders are deprecated as of rails 4.0 (edgeguides.rubyonrails.org/…) so it's probably not a good habit to learn now.Manton
R
2

Other alternative:

Foo.find(:first, conditions: { bar: 'a-value' })

You can also use multiple attributes:

Foo.find(:first, conditions: { bar: 'a-value' , wibble: 'a wibble value' })
Runnymede answered 11/3, 2014 at 17:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.