calyxofheld
calyxofheld

Reputation: 2128

undefined method '+' for nilClass when using first_or_create

I have a function that uses first_or_create on a record, and I need to be able to use + on one of its attributes in the event that it exists.

Blob.where(user_id: user.id, item_id: item.id).first_or_create do |s|
  s.amount += amount
end

However, I cannot use + if the record does not exist. Is this a syntax issue or is it my use of first_or_create?

Upvotes: 1

Views: 280

Answers (2)

Alex Santos
Alex Santos

Reputation: 2950

The block is only called when a new object is created (one has not been found). If the model doesn't have a default value for the given field, it will try to call + on a nil value. You can do something along these lines (there might be a nicer way):

blob = Blob.where(user_id: user.id, item_id: item.id).first_or_create
blob.amount += amount if blob.amount.present?

In this situation, you only perform the sum if the object already exists (which seems to be your goal according to your description). If you want to apply the amount sum in any situation, you can initialize the amount to 0 if the record does not yet exist:

blob = Blob.where(user_id: user.id, item_id: item.id).first_or_create do |b|
  b.amount = 0
end
blob.amount += amount

In the example above, if a object exists then it will add amount to the current value, otherwise it will initialize the attribute with 0 and then add amount to it.

Upvotes: 5

jhpratt
jhpratt

Reputation: 7130

Perform a null check on s.amount. If it doesn't exist prior, s.amount will be nil, which naturally can't be added to.

You can do this by using the following.

Blob.where(user_id: user.id, item_id: item.id).first_or_create do |s|
  if s.amount.nil?
    s.amount = amount
  else
    s.amount += amount
  end
end

Alternatively, you could probably set a default of 0 on the field, though I'm not positive on that one.

Upvotes: 1

Related Questions