You seem to need the find_or_create_by_* method.
To avoid a loop, you should not place it in the save method, but in one of these two places:
Option 1: Controller Level
In the controller where you create the UserActivity instance, instead you write:
a = UserActivity.find_or_create_by_user_id_and_activity_id(user_id: user_id, activity_id: activity_id) a.update_attributes start_at: start_at, end_at: end_at.....
Option 2: class method
If you find that you are adding the above code to several contrllers, the best way would be to define a new class method in UserActivity :
class UserActivity def self.create_or_update_from_attrs(user_id, activity_id, start_at, end_at...) a = UserActivity.find_or_create_by_user_id_and_activity_id(user_id: user_id, activity_id: activity_id) a.update_attributes start_at: start_at, end_at: end_at..... end end
And in controllers, obviously:
UserActivity.create_or_update_from_attrs(...)
Replace save
Of course, you can override the save method, but this duplicates the functionality of Rails ( find_or_create_by... ) and, as such, violates DRY and , you can shoot yourself with your foot some time later when it contradicts any other situation that you encounter therefore I do not recommend using this:
EDIT: updated to avoid endless loop
class UserActivity def save # If this is new record, check for existing and update that instead: if new_record? && a = UserActivity.where(user_id: user_id, activity_id: activity_id).first a.update_attributes start_at: start_at, end_at: end_at ... return true # just to comply with Rails conventions else # just call super to save this record super end end end