I'm working with a Ruby on Rails application where it was authored to generate some files in the after_save callback. The paperclip gem is used in the class. When these files are created, save is called on the Ruby object which triggers a loop of this second save calling after_save which calls save which calls after_save and on and on.
save! -> after_save -> save! -> after_save!
Eventually somehow the app breaks out of this loop on its own. I'm not sure how.
My question is, if I have an attribute on a class that is changed?=true, when does changed? get flipped to false? We use a changed? check as a sort of gate to prevent this file creation from happening and it seems like changed is always true every time it enters the after_save code. I would've thought that in after_save, changed? would be false by now since the data has been saved.
You should use after_commit with a condition of the key (attribute) present in the previous_changes.
http://apidock.com/rails/ActiveModel/Dirty/previous_changes
Related
I just want to manipulate a model level object when it is newly created or it is updated.
For example, consider there is a test table with name attribute:
class Test < ActiveRecord::Base
custom_callback :hi
def hi
name = "h"
end
end
m = Test.new(:name => "hello")
m.save
I just want to write a custom callback which should get executed before_validation and should get executed whenever a save or save! is called. Ideally, I want some callback in rails 2.3 which should get executed and hook into ActiveRecord::Base. is there any gem to do this or does anyone know how to write a callback which get executed before 'before_validation' callback?
You could override the save and save! methods to effectively inject the code. There's also the initialize method that might be appropriate depending on what you're trying to do. Also, before_validation runs before validate, so how much earlier do you need it to run exactly, and why?
Can you say more about why you want to do this? It sounds like you may have a design problem and you're trying to find a hack instead of addressing a more fundamental issue.
It seems you are looking for before_save, which runs after validation: http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
Please refer to This answer
I'm using mongoid, and I want to migrate my documents one at a time. To do this, I've tried doing the migration in an after_initialize callback, but I can't seem to save() from there without triggering the same validation and infinite recursion. Is there a better callback to use, or a different thing I should be looking at?
Have you tried passing :validate => false into the save? That allows you to bypass validations.
As per the original question,
instance.update_attributes(new_attr_hash)
will immediately save after updating the instance, but you can't bypass validations with update_attributes.
I'd use before_save, and then go through the whole collection and save them again outside the callback, instead of just initializing them like I assume you were doing before.
Are after_create and after_save the same as per functionality?
I want to do an operation with the email of a user after its account creation.
I want to do that operation when it is saved in the database.
which is preferable to use: after_create or after_save?
after_create only works once - just after the record is first created.
after_save works every time you save the object - even if you're just updating it many years later
So if you want to do this email operation only just the once (and then never again) then use after_create.
If you want to do it every time the object is saved, then do it in after_save
From the docs:
after_create()
Is called after
Base.save on new objects that haven‘t
been saved yet (no record exists).
after_save()
Is called after Base.save
(regardless of whether it‘s a create
or update save).
after_save()
Works fine when you have to save models that do not save very often.
For this particular example of changing records frequently it would be advisable to use
after_commit()
make sure that the model is saved in the database before the action is executed
after_commit :calculate_credit_score
def calculate_credit_score
#Call a Cron job
end
I have an ActiveRecord object. It is updated using the nested attributes of a parent object. The problem is it has some non-database fields which if set need to trigger an after_save event. The problem that I am having is that if no database attributes are updated the after_save never fires, but I need it to.
ActiveRecord.partial_updates = false is a default in my app. The save never happens...
I tried to update the updated_at = DateTime.now and it does not trigger the record to be saved. Only when one of it's other properties gets updates does the save actually trigger.
Note Rails 2.3.8
Though I haven't tested it, it's possible that including ActiveModel::Dirty and telling it about those non-database fields will allow ActiveRelation pick them up.
More info: http://railsapi.com/doc/rails-v3.0.3/classes/ActiveModel/Dirty.html
Basically I manually created a setter for the non database property and invoked id_will_change! which made the whole object dirty. This works for my needs.
I have an ActiveRecord model with a status column. When the model is saved with a status change I need to write to a history file the change of status and who was responsible for the change. I was thinking an after_save callback would work great, but I can't use the status_changed? dynamic method to determine that the history write is necessary to execute. I don't want to write to the history if the model is saved but the status wasn't changed. My only thought on handling it right now is to use an instance variable flag to determine if the after_save should execute. Any ideas?
This may have changed since the question was posted, but the after_save callback should have the *_changed? dynamic methods available and set correctly:
class Order
after_save :handle_status_changed, :if => :status_changed?
end
or
class Order
after_save :handle_status_changed
def handle_status_changed
return unless status_changed?
...
end
end
Works correctly for me w/ Rails 2.3.2.
Use a before_save callback instead. Then you have access to both the new and old status values. Callbacks are wrapped in a transaction, so if the save fails or is canceled by another callback, the history write will be rolled back as well.
I see two solutions:
Like you said: add a variable flag and run callback when it is set.
Run save_history after updating your record.
Example:
old_status = #record.status
if #record.update\_attributes(params[:record])
save_history_here if old_status != #record.status
flash[:notice] = "Successful!"
...
else
...
end
Has anyone not heard of database triggers?
If you write an on_update database trigger on the database server, then every time a record gets updated, it will create a historical copy of the previous record's values in the associated audit table.
This is one of the main things I despise about Rails. It spends so much time trying to do everything for the developer that it fools developers into thinking that they have to follow such vulgar courses of action as writing specialized rails methods to do what the freaking database server already is fully capable of doing all by itself.
shakes head at Rails once again