Ruby and Rails have many magic features like blocks/closures, duck typing/mix-ins/modules, method_missing, poetry mode.
One of the common tasks in programming web applications on Rails is finding a row in a table by several columns and creating a new row in case of row is missing.
Find by one attribute
This will find a row by ‘name’ column in table ‘Products’ and will create a new row if not found.
[codesyntax lang=”rails”]
Product.find_or_create_by_name(‘name here’)
[/codesyntax]
If you want a new row to be created with many other attributes then you can pass them as a hash:
[codesyntax lang=”rails”]
Product.find_or_create_by_name(‘namehere’, :category_id=>1, :enabled=>true, :in_stock=>0, :price=>100)
[/codesyntax]
Find by multiple attributes
If you want to find by multiple attributes you can use model’s methods like find_or_create_by_field1_and_field2(field1_value, field2_value).
[codesyntax lang=”rails”]
Product.find_or_create_by_name_and_category_id(‘namehere’, 10)
[/codesyntax]
If you want to pass multiple attributes to a new row to be created then you can use the following syntax:
[codesyntax lang=”rails”]
Product.find_or_create_by_name_and_category_id(‘namehere’, 10) do |r|
r.price= 100
r.available = true
r.enabled=1
r.in_stock=0
end
[/codesyntax]
Notice that you cannot pass extra parameters to Product.find_or_create_by_name_and_category_id method because it expects only two parameters. Thanks Rails this method can be passed a block with your code and this code will be invoked for the new row to be initialized.
Without all that Ruby’s magic the task could be achieved with the following code:
[codesyntax lang=”rails”]
attr = { :enabled=>true, :in_stock=>0, :price=>100}
row = Product.find_by_name_and_category_id(‘namehere’, 10) || Product.create(attr)
[/codesyntax]
You must agree that this code looks not so elegant and concise.
Details are here on Github