Rails: create or update in model saving - ruby-on-rails

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?

Related

Find out if inside a model callback

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

What happens during each of the ActiveRecord model lifecycle stages?

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.

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.

is there any way to forcefully imply validation on update_all

I have a Rails application I am using update_all to updates but as we know it is skipping the validations how can I forcefully apply validation on this update_all
From the API docs (emphasis my own).
Updates all records with details given if they match a set of conditions supplied, limits and order can also be supplied. This method constructs a single SQL UPDATE statement and sends it straight to the database. It does not instantiate the involved models and it does not trigger Active Record callbacks or validations.
No, there is not a way to force validations when calling update_all. The purpose of update_all is to modify records in bulk without instantiating model instances for each record. A model instance must exist for a record to have validations called against it.

Safe to override save method in ActiveRecord?

In a particular class that extends ActiveRecord::Base, I need to update a different ActiveRecord object whenever this one is created. Is it safe to override the save method and do the following in the save?
def save
super
other = self.other
other.name = self.name
other.save!
end
I'm worried about potential transaction related issues. I assume this would all be 1 transaction, if any part fails, everything is rolled back?
Is there a particular reason why you wouldn't use the hooks provided for this purpose?
You've got after_create, after_save, after_update, before_create, before_save, before_update - and a bunch of others. Wouldn't one of those be suitable?
In fact, given what you've said, it sounds like before_save is what you want, as you can catch any errors that occur whilst saving the second model and prevent the first one from being saved (by returning false from the before_save call).

Resources