40

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?

John Bachir
  • 22,495
  • 29
  • 154
  • 227
  • 2
    I actually quite like the old find_by_*. The intent is clear, and if that's all you need, the syntax is simpler. – Matthew Rudy Jun 13 '11 at 20:04
  • 1
    And its still perfectly valid in Rails 3. If using Rails 4, you can use `find_by(bar: 'a-value')`. – sevenseacat Aug 02 '13 at 15:11
  • 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](https://stackoverflow.com/questions/6326440/best-way-to-find-a-single-record-using-activerecord-3-arel/66600205#answer-66600205) :) – SRack Mar 12 '21 at 12:47

5 Answers5

50

Rails 4 :

Foo.find_by( bar: 'a_value', wibble: 'a wibble value' )
Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
SureshCS
  • 1,005
  • 12
  • 23
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.

nmunson
  • 902
  • 8
  • 11
  • 4
    Use `Foo.where(:bar => 'a-value').first!` if you want to ensure a record is found. That way `ActiveRecord::RecordNotFound` will be raised otherwise. – iltempo Mar 23 '14 at 20:05
6

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.

Andrew Smith
  • 162
  • 5
SRack
  • 11,495
  • 5
  • 47
  • 60
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')
Will Tomlins
  • 1,436
  • 16
  • 12
  • 11
    These dynamic finders are deprecated as of rails 4.0 (http://edgeguides.rubyonrails.org/4_0_release_notes.html#active-record-deprecations) so it's probably not a good habit to learn now. – Wes Oldenbeuving Feb 07 '14 at 15:58
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' })
Victor Lellis
  • 1,304
  • 1
  • 14
  • 25