Ruby on Rails is designed to achieve more with less code. A perfect example of this is its use of Dynamic Finders.


In this example I will use an Post model. This is now it is defined in the database:

create_table "posts", :force => true do |t|
  t.string :name,
  t.string :category
end

Dynamic Finders for Fetching Objects

If your not used to using dynamic finders you would have coded your find queries similar to this:

  Post.find(:all, :conditions => ["name = ?", name])

With dynamic finders you can use a number of special find methods to get what you need using simpler syntax. You can use the find_by_and find_all_by_ methods with your model to return objects without need to use the :conditions option.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Fetch record of the name 'Active'
Post.find(:first, :conditions => ["name = ?", "Active"])
Post.find_by_name("Active")
 
# Fetch all the records with the name 'Active'
Post.find(:all, :conditions => ["name = ?", "Active"])
Post.find_all_by_name("Active")
 
# Fetch records with the name 'Active' and the category 'Rails'
Post.find(:all, :conditions => ["name = ? AND category = ?", "Active", "Rails"])
Post.find_by_name_and_category("Active", "Rails")
 
# Fetch posts with the name variable, and order by name DESC
Post.find(:all, :conditions => ["name = ?", name], :order => "name DESC")
Post.find_all_by_name(name, :order => "name DESC")

Dynamic Finder for Creating Object

There are times when you would need to find for a particular object, and then either use the object or if it doesn’t exist, create a new one. If we use the same Post model as above, if would normally be done this way:

post = Post.find_by_name(name)
if(!post)
  post = Post.create(:name => "Active")
else
  # Code for using the post object
end

Rails make this must simplier by providing find_or_create_by and find_or_initialize_by. The find_or_create_by returns an object if found, otherwise will create, save and return a new object. The find_or_initialize_by will return an object if found, but will only create and return a new object (without saving).

# No posts with name 'Active' exists, so a post is created and stored into post object
post = Post.find_or_create_by_name("Active")
 
# A post is found with the name 'Active' and stored into the post object
post = Post.find_or_create_by_name("Active")
 
# A new post object is create with its name 'Record' but is not saved into database
post = Post.find_or_initialize_by_name("Record")