Read more

Find an ActiveRecord by any column (useful for Cucumber steps)

Henning Koch
February 17, 2012Software engineer at makandra GmbH

The attached patch lets you find a record by a string or number in any column:

User.find_by_anything('carla')
User.find_by_anything('email@domain.de')
User.find_by_anything(10023)
Illustration UI/UX Design

UI/UX Design by makandra brand

We make sure that your target audience has the best possible experience with your digital product. You get:

  • Design tailored to your audience
  • Proven processes customized to your needs
  • An expert team of experienced designers
Read more Show archive.org snapshot

There's also a bang variant that raises ActiveRecord::NotFound if no record matches the given value:

User.find_by_anything!('carla')

Boolean and binary columns are excluded from the search because that would be crazy.

I recommend copying the attachment to features/support/find_by_anything.rb, since it is most useful in Cucumber step definitions (see below).

Application in Cucumber step definitions

You should use this in step definitions that look up a record by some identifier. This makes your step much more flexible, since now you won't have to go out of your way to create scenarios where e.g. users have known screen names, e-mail addresses, full names, etc., only because your step definition requires that.

Here's a typical step definitions that benefits from using find_by_anything:

When /^I sign in as "([^\"]+)")$/ do |identifier|
  user = User.find_by_anything!(identifier)
  visit new_session_path
  fill_in 'E-mail', :with => user.email
  fill_in 'Password', :with => "secret"
  click_button 'Sign in'
end

You can now use any of the following steps:

When I sign in as "carla@domain.de"
When I sign in as "Carla"
When I sign in as "carcar79"

Patch to make it work for Rails 2

For Rails 2, the last line of find_by_anything needs to be changed to:

find(:first, :conditions => [query_clauses.join(' OR '), *bindings])
Posted by Henning Koch to makandra dev (2012-02-17 10:23)