The following blog post contains material either currently found or soon to be incorporated into my new book, "Easy Active Record for Rails Developers". Among many other topics, you'll learn about model generation, migrations, validations, associations, scopes, joins, includes, forms integration, nested forms, and model testing with RSpec and FactoryGirl. The book is now available, head over to this website's home page to learn more.


One of my favorite Active Record features is the so-called magic finder find_or_create_by. It’s one of those truly pragmatic conveniences that Rails offers to help developers do more faster. The find_or_create_by finder saves you the hassle of writing additional logic to create a new record should an existing record associated with a particular attribute not already exist. For instance, suppose your application managed among other things a list of arcade game publishers, and you wanted to create a new record for the famed publisher Namco if a record did not already exist. You can do so using find_or_create_by_name:

publisher = Publisher.find_or_create_by_name('Namco')

Mind you I didn’t pull find_or_create_by_name out of a hat; Active Record will know to presume that whatever string appears at the end of find_or_create_by is an attribute associated with the Publisher model. For instance, if the Publisher model included a url attribute then the method find_or_create_by_url is also recognized. Therefore, in this case, Rails will know to consult the publishers table’s name field in order to determine whether a record identified by the name Namco already exists.

Presuming you’re running Rails 4 then you’ll want to use the following preferred syntax:

publisher = Publisher.find_or_create_by(:name => 'Namco')

Whether you’re running Rails 3 or 4, most developers don’t realize the find_or_create_by syntax can be extended to consult multiple attributes. For instance you could determine whether a publisher having the name Namco America and URL www.namcoamerica.com exists and if not create it using the following syntax:

publisher = Publisher.find_or_create_by_name_and_url('Namco', 'http://www.namcoamerica.com')

Again, Rails 4 users will want to instead use this variant:

publisher = Publisher.find_or_create_by(:name => 'Namco', :url => 'http://www.namcoamerica.com')

Although this example illustrates find_or_create_by method’s ability to use multiple attributes, admittedly this example is a bit contrived because one could safely presume each manufacturer will be identified solely by its trademarked name, making a multiple key such as this rather superfluous. Instead, you’ll likely want to search the publishers table for a publisher named Namco, and if it doesn’t exist, create it using the supplied name and URL. You can do so by using find_or_create_by in conjunction with create_with:

publisher = Publisher.create_with(:url => 'http://www.namcoamerica.com').find_or_create_by_name('Namco')

And once again, the Rails 4 syntax:

publisher = Publisher.create_with(:url => 'http://www.namcoamerica.com').find_or_create_by(:name => 'Namco')

Like what you read? There’s plenty more where this came from in my new book, “Easy Active Record for Rails Developers”!

Comments