Find out if inside a model callback - ruby-on-rails

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

Related

Only call Rails Active Record callback on successful model create

I want to add after_create :my_function to one of my models. How can I make sure this method is only called on successful creates or updates?
You'd want to use after_save. This callback is called on both create and updates (or, any call to the save method) so long as the callback chain isn't broken before the save completes (validation errors, etc). You can see some examples in the docs:
http://apidock.com/rails/ActiveRecord/Callbacks/after_save

how exactly does rails callbacks work

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.

How can I distinguish between direct instantiation and instantiation through an association in Rails?

I have an after_initialize callback that I would like to happen whenever the model is created or instantiated directly, as opposed to loaded through an association in some other place. Something like this:
after_initialize :check_status, if: "instantiated_directly?"
such that MyModel.find(1) will trigger the check, but other_model.my_model will not.
The status is a state variable for a long process, which only needs to be verified before some long-running process starts. I want to prevent the user from loading the model if the process seems to be in progress. I'd like to still be able to acces attributes in that model for various other reasons elsewhere.
Preventing the read is probably not the best vector for ameliorating this issue, nor is a model that tries to reach out of its own scope to determine how to load a wise idea. I would instead recommend you simply add a validation to ensure the record can be modified without interfering with your background processes, a la…
validate :safe_to_edit?
def safe_to_edit?
some_state_variable
end
Your model also exposes a safe_to_edit? method here that allows your controller or another object to determine the best behavior independently of checking validations, such as if you had a client-side service polling to flag the user when it was safe to edit, or you wanted to delay response and try again in a few seconds in a background job, etc.

Rails: create or update in model saving

I have a model (Bookmark) with two fields, call them A and B.
When creating a new model i have to perform a rather complex check on B and, if true update a Bookmark in the database (setting A to the one being passed) and abort the creation, if false just keep it on and create a new Bookmark.
So I set a before_create filter. The problem with the function called is that if I perform an update_attributes on a retrieved object from it and then return false (in order to abort the saving), the update is not performed (for some reason I don't know).
update_attributes returns true and there are no errors, but in the log i only see
SQL (0.2ms)
If i don't return false, the record is correctly updated, but it also inserts a new record (and I don't want this). Any help?
Canceling callbacks
If a before_* callback returns false, all the later callbacks and the associated action are cancelled. If an after_* callback returns false, all the later callbacks are cancelled. Callbacks are generally run in the order they are defined, with the exception of callbacks defined as methods on the model, which are called last.
http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
When using callbacks, any call to update_attribute from within the before_create callback will bork it.
I was bitten unexpectedly by this as well. I think the source for this came from the rails api, in a one liner, or a blog post that escapes me right now, sorry.
This complicated call isn't a validation though?
Or maybe you can pull out the update_attribute and use it after the complicated logic?

Should a model method call 'save' itself?

Let's say that we have a method inside a model that
needs to called only on saved records
may update the model itself and thus the model needs to be saved again afterwords
Should the "save" calls happen inside the method itself like the following code
def result
save! if new_record?
# do some funky stuff here that may also change the model state
# ...
# And calculate the return value
search_result = "foo" # Let's say "foo" is the value we calculated
save! if changed?
search_result # return
end
Or should the external observer (the controller) be responsible for calling save as needed?
If your method really, really needs to do all that, so be it.
However, I would make it clear from looking at the method why you're doing that (comments might be good here), and would definitely make this a bang_method! so that it is clear to whoever invokes it that this method is liable to mess with the object as much as it likes.
Also, the method name result (which, I know, probably isn't your real method name) somewhat implies that you're just fetching data, and little more. Maybe load_result! would be more appropriate here, to make it clearer that you're not just accessing an attribute, but are, in fact, performing heavy operations to get it.
There are definitely times when it is necessary for a model to persist itself. But it's worth considering whether save is the best method for your application.
In a current example, we have a model that processes a file asynchronously in a long-running method (we are spinning the process off using sidekiq.) Inside the method, a persistent attribute is updated regularly so the status information is available to other requests.
We're using update_column rather than save, because
We don't want or need the overhead of the AR callbacks, and we particularly want to skip validation to ensure the update occurs surely and immediately.
We only need to update a single attribute. Using update_column avoids the need to determine whether any other attributes need to be saved (or not saved.)
Inside the model, methods like
update_column
save(:validate => false) (granted, same method, but different options)
touch
etc, may often be a more appropriate way to persist changes than a plain save.
When does a program save data on a file?
a) Only when user requires it (directly or indirectly)? -- this is controller case
b) Only when the program achieves part of its correctness and data integrity? -- this is model case
c) Both.
I would vote for (c). I hope this discrimination straightens things a bit.
Additionally, from a object-oriented design point of view, method save() belongs to the public contract of its class; it can be invoked by anyone. Given this, a class is responsible for its public contract and, if needed, an object can invoke its own methods at will.

Resources