I'm curious how exactly those callbacks work. If i initialize an object, and then use method save to throw it into my database, will before_create callback work?
Similar thing with before_save. is it called literally only before function save is being used, or will it be triggered also in case of using create method?
before_save will be triggered before you save a record. It doesn't matter whether you're creating or updating a record, your callback will be triggered. So, yes, it will also be triggered when you use the create method.
before_create is only triggered before creating a record, not before updating a record.
There is also before_update, which is only triggered before updating, but not before creating.
This doesn't depend on which method you use, it depends on whether the record was persisted before or not. In other words, it depends on whether you're updating or creating a record.
http://api.rubyonrails.org/v4.1.1/classes/ActiveRecord/Callbacks.html this url will help you find right answer for you. On this url you can also find the sequence for call back. Hope it helps you.
Related
Sometime I want a method which can be used standalone and within Rails callback to behave a little differently. I want save() call inside my method to be ignored if it is within callback.
So is there a method in Rails to say if I am currently in the context of ActiveModel callback. The last resort would be using backtrace, but I hope there is a nicer solution.
update
My model has some kind of state machine. One event transition is make_bid. During the before_create, I want to call that and create a Bid. If creation succeeds, make_bid then sets the state to be bidded.
Now, it makes sense to save in this method, since it is a event transition method. However if save is called, since it is in a before_create, stackoverflow would occur.
This make_bid method is also being called from other contexts which are not model callbacks, which we do want save.
So the only way is to find out whether we are within a callback, if it is, then don't save, otherwise, save.
You can set a flag to avoid infinite recursion:
def make_bid
return if #making_bid
#making_bid = true
...
save
#making_bid = false
end
I cannot find documentation describing what happens during each of the ActiveRecord lifecycle stages. The Guide and API list the available callbacks.
How would I know which callback is appropriate if I don't know the state of the model, or what took place earlier in the lifecycle?
For example, when does the model get persisted, and gain an id? The guide lists callbacks:
3.1 Creating an Object
before_validation
after_validation
before_save
around_save
before_create
around_create
after_create
after_save
after_commit/after_rollback
So, I'm pretty sure that the model hasn't been persisted, and doesn't have and id, before before_save is called. I would expect the model to have and id before after_save is called. Unfortunately, I have no idea where, between those 2 calls the model was persisted, and gained its id.
EDIT
Again, this is purely one example. I have updated the question to clarify: "What happens during each of the ActiveRecord model lifecycle stages?"
Actually I can't provide you a link where all this stuff is explained.
But if I were you, I'd implement a method that will be invoked on each of these callbacks, and it could help to find out, when model gaines its id.
The "save" action is when the query to insert the record into the database is executed, and it is generally this action that will assign an id.
I can't say for sure that there aren't exceptions, but id's are usually assigned by the database during the insert process. The assigned id can be passed back to the application as part of the insert statement.
In Rails, I would like to be able to have a model that checks if a value for a column signature already exists, if it does not, save it, if it does, update the existing model and then exit out. This has to be a model solution. I cannot use controller logic to achieve this, it has to be automatic.
I have tried using filters like before_create or before_save, but it doesn't seem like there is a clean way to stop the filter chain and update an existing record by those means. Any help is appreciated. Thanks.
The code below is for a method that you could use instead of save. It checks if a model exists with the same signature. If it finds one, it updates that existing model with the attributes and then return that model. If there is no other model that has that signature, it will continue on saving. You will have to use this in place of ActiveRecord's #save in places where you want this behavior. There was no way to do this using callbacks since the only way to cancel saving in a callback was to have it return false.
def save_signature
model = Model.find_by(signature: signature)
if model
model.update(attributes)
model
else
save
end
end
Let me know if I understood what you wanted. If not, then just point out what I misunderstood and I'd be happy to change my answer accordingly.
Maybe not the cleanest way but why to stop the chain?
fetch the object on before_* filter, do the check and update the model, it will be saved with the old value.
what do you think?
Read about find_or_create_by http://guides.rubyonrails.org/active_record_querying.html#find-or-create-by . This will either create a new record or output you the previous one. Hopefully it may work for you
The issue that my application is already alive and bunch of user's use data, in which I found bug and fixed it in the code. But how can I modify their data with edited method, which is actually is before_save callback?
I have their input for this record stored in another column, I need to modify output.
How I can do this?
Do you mind if the updated_at value of your model changes?
If not, I suppose you could loop through your model collection calling the save method.
> Foo.all.each(&:save)
If you go this way, you better stop your application before you make changes to the database.
I want to log the user who destroyed a record using before_destroy callback. But, I dont know how to pass arguments to before_destroy(and I am not sure if it is possible). Maybe I am dealing this in the wrong way. Any other perspective to do this will also do.
Create a virtual attribute on the Record model called destroyer or something.
Then you can do whatever you want with that attribute in your before_destroy callback.