Question

I have the following table:

event_id  value   created_at        updated_at
1         15.2    2014/01/01 00:00  2014/01/01 00:00
2         15.5    2014/01/01 00:10  2014/01/01 00:10
3         15.9    2014/01/01 00:20  2014/01/01 00:20

However, if a new Event has same value as the previous (as in newest in time) Event, then the previous Event should have "updated_at" set to current time and no new Event should be created.

In the example above, if I do Event.new(:value => 15.9), then Event with id 3 should have its updated_at set to current time - and that should be the only change.

Any suggestions on how to accomplish this? I have tried fiddling with Active Record callbacks, but fail when aborting creation (using rollback). It is of course possible to solve using a special "constructor" method, but I'd like to avoid that.

Was it helpful?

Solution

Event.where(value: params[:value]).first_or_create.touch

or in event.rb

before_save :update_if_existing

private 
def update_if_existing
  if event = Event.find_by(value: value)
    event.touch # updates the updated_at timestamp if the existing event
    false       # prevents the current event from being inserted into the db
  end
end

OTHER TIPS

Event.find_or_create_by_value(params[:value]).touch

This method will find event by value or create one if event with this value doesn't exist. Touch method will update updated_at timestamp for this record.

You can do this way, let's say @event is the object and before saving you want to check the value

unless @event.value == Event.last.value     
  @event.save
else
  Event.last.update_attributes(:updated_at => DateTime.now)
end

or you can do this in a single line using ternary operator

(@event.value == Event.last.value) ? (Event.last.update_attributes(:updated_at => DateTime.now)) : (@event.save)

Since your definition of Event is that no two events should have the same value - you should add a unique index on that field, which will also make any such operations much quicker.

Actually, since your event is not defined by its id but by its value, consider changing its primary key to value:

create_table(:event, :primary_key => 'value') do |t|
  t.column :userID, :decimal, :null => false
  ...
end

class Event
  set_primary_key :value
  ...
end

Now you can simply do:

Event.find_or_create_by_value(params[:value]).touch
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top