Reputation: 4505
The #new_record? function determines if a record has been saved. But it is always false in the after_save
hook. Is there a way to determine whether the record is a newly created record or an old one from update?
I'm hoping not to use another callback such as before_create
to set a flag in the model or require another query into the db.
Any advice is appreciated.
Edit: Need to determine it in after_save
hook, and for my particular use case, there is no updated_at
or updated_on
timestamp
Upvotes: 124
Views: 78011
Reputation: 4663
There is a method called previously_new_record?
for exactly this use case.
user = User.new
user.new_record? # => true
user.previously_new_record? # => false
user.save
user.new_record? # => false
user.previously_new_record? # => true
Looks like the proposed workaround by calling saved_change_to_id?
doesn't work anymore. I'm on Rails 7.
Upvotes: 17
Reputation: 154
For Rails 4 (checked on 4.2.11.1) results of changes
and previous_changes
methods are empty hashes {}
on object creation inside after_save
. So attribute_changed?
methods like id_changed?
won't work as expected.
But you can take advantage of this knowledge and - knowing that at least 1 attribute has to be in changes
on update - check if changes
is empty. Once you confirm that it's empty, you must be during object creation:
after_save do
if changes.empty?
# code appropriate for object creation goes here ...
end
end
Upvotes: 1
Reputation: 2590
Rails 5.1+ way:
user = User.new
user.save!
user.saved_change_to_attribute?(:id) # => true
Upvotes: 16
Reputation: 9742
I was looking to use this for an after_save
callback.
A simpler solution is to use id_changed?
(since it won't change on update
) or even created_at_changed?
if timestamp columns are present.
Update: As @mitsy points out, if this check is needed outside of callbacks then use id_previously_changed?
. See docs.
Upvotes: 199
Reputation: 12086
Since the object has already been saved, you would you need to look at the previous changes. The ID should only change after a create.
# true if this is a new record
@object.previous_changes[:id].any?
There is also an instance variable @new_record_before_save
. You can access that by doing the following:
# true if this is a new record
@object.instance_variable_get(:@new_record_before_save)
Both are pretty ugly, but they would allow you to know whether the object has been newly created. Hope that helps!
Upvotes: 19
Reputation: 332
There is an after_create
callback which is only called if the record is a new record, after it is saved. There is also an after_update
callback for use if this was an existing record which was changed and saved. The after_save
callback is called in both cases, after either after_create
or after_update
is called.
Use after_create
if you need something to happen once after a new record has been saved.
More info here: http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
Upvotes: 23
Reputation: 9789
Yet another option, for those who do have an updated_at
timestamp:
if created_at == updated_at
# it's a newly created record
end
Upvotes: 30
Reputation: 7127
No rails magic here that I know of, you'll have to do it yourself. You could clean this up using a virtual attribute...
In your model class:
def before_save
@was_a_new_record = new_record?
return true
end
def after_save
if @was_a_new_record
...
end
end
Upvotes: 33