DataMapper update_or_create
October 13th, 2010
Source code: git repository at github
DataMapper has a defined method named first_or_create, very explicit name, that takes a condition and attributes as params. Its source code defined in dm-core-1.0.2/lib/dm-core/model.rb is:
def first_or_create(conditions = {}, attributes = {})
first(conditions) || create(conditions.merge(attributes))
end
What is does is simply find the first resource by conditions, or create a new resource with the attributes if none found. This always returns an instance of the resource found or created.
It became handy to create an update_or_create method, so I created:
module DataMapper
module Model
def update_or_create(conditions = {}, attributes = {}, merger = true)
(first(conditions) && first(conditions).update(attributes)) || create(merger ? (conditions.merge(attributes)) : attributes )
end
end # Module Model
end # Module DataMapper
There are differences to consider, like the merger param and the returned TrueClass bool upon update (and not an instance of the resource).
I found a merger param necessary because of the Serial type of properties. In the implementation of first_or_create method if we specify a Serial property as a search condition and the search has no success, then the conditions will be merged with the attributes and the Serial +1 will not be taken in account. Thus, in this implementation setting merger to false, search conditions will not be merged. Some examples:
Article.update_or_create({:id => 10}, {:name => "Spirou meet Franquin"})
If Article with ‘id’ 10 exists then it will receive a new name
If Article with ‘id’ 10 doesn’t exist, it will be created with {:id => 10, :name => “Spirou meet Franquin”}
Article.update_or_create({:id => 123}, {:name => "Fantasio meet Franquin}, false)
If Article with ‘id’ 123 doesn’t exist, it will be created with {:name => “Fantasio meet Franquin”} and a self sequential id:
EDIT: new implementation to always get a DataMapper Object: