Fred Fred - 5 months ago 14
Ruby Question

DataMapper first_or_create always set certain field?

I'm using the following with datamapper to create/get a new user from my db:

user = User.first_or_create({:id => data['id']})


This gets the user with id = data['id'] or creates it if it doesn't already exist.

I want to know how to set other attributes/fields of the returned object regardless of whether it is a new record or existing?

Is the only way to do this to then call
user.update({:field => value ...})
or is there a better way to achieve this?

Answer

Well, you could write it as one line:

(User.first_or_create(:id => data['id'])).update(:field => value)

with hashes for the parameters if you wish (or if you need to specify more than one); however, it's worth noting that this will only work if the model as specified by the first_or_create is valid. If :name were a required field, for instance, then this wouldn't work:

(User.first_or_create({:id => data['id'], :name => "Morse"})).update(:name => "Lewis")

as the creation in the first part would fail.

You could get around this by specifying the parameters needed for a new record with something like

(User.first_or_create({:id => data['id'], :name => "Morse"}, {:name => "Lewis"})).update(:name => "Lewis")

but this is unusually painful, and is difficult to read.

Also note that using first_or_create with an :id will attempt to create a model with that specific :id, if such a record doesn't exist. This might not be what you want.

Alternatively, you can use first_or_new. You can't call update on an object created using this, however, as the record won't exist (although I believe this might have worked in previous versions of DataMapper).