is there any way to forcefully imply validation on update_all - ruby-on-rails

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.

Related

RAILS: Prevent creating a record twice if two requests are sent at the exact same time

I'm using an external API which for whatever reason posts every request twice at the exact same time. This is out of my control.
This causes records to be created twice in my mysql database.
I do have a validation in my model that checks if a record exists. This works fine if the two requests are sent after each other, but doesn't work if the two requests are sent at the same time.
The only thing I can think of is creating a job for each request that is executed at some random amount of time from now and validating the uniqueness in my model. But I wonder if there is a better way of dealing with this?
So how do I deal with this issue?
What may help you is adding a unique validation to your model and uniqueness constraint to the DB itself. The reason is that the model validation won't be enough, it will be needed just to make your application "aware" of that restriction. What will actually prevent you from saving two duplicate records is the DB constraint.
So when two duplicating requests will successfully pass your validation, the first of them will create a record and the second will try to do so, too, but MySQL adapter will raise ActiveRecord::RecordNotUnique which you'll be able to handle.
That's actually nothing more than a common way to handle race conditions. So basically add unique index to the corresponding table and it will do the trick.
Active Record uniqueness validation does not guarantee uniqueness at
the database level
The solution is straightforward to implement, you just need to enforce
uniqueness at the database level as well as at the model level.
You can create a database index and then require that the index to be unique
The documentation actually suggests the same
uniqueness helper validates that the attribute's value is unique right
before the object gets saved. It does not create a uniqueness
constraint in the database, so it may happen that two different
database connections create two records with the same value for a
column that you intend to be unique. To avoid that, you must create a
unique index on that column in your database.

Update attributes without touching the database in Rails

I have a situation where I have an ActiveRecord::Relation object, where the relation's objects have some has_many associations. There is another piece of code that deletes the database rows associated with this relation that doesn't go through the relation, using delete_all. I know what the new state of the relation's associations is even without going to the database so I want to be able to set the object's attributes in this relation manually without touching the database again.
I found this article which mentions the write_attribute method. This works, but it looks like it has been deprecated, so I'd rather not use. It also mentions attributes= as a way of doing this without accessing the database. Is there something that can achieve the effect of write_attribute where I won't access the database when modifying a relation's attributes?
assign_attributes
It's like update_attributes, without saving.

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.

use Rails validations to limit to one currently active model

Using Rails 3 validations and/or callbacks, what would be the cleanest way to ensure that only one record of a model has a boolean value ticked as true? I'd like to mark one record as the currently active model.
(I know another option is to use a has-one association, but I'm curious to know how to store this more directly in the model records.)
If all you want to do is validate it you can use
validates_uniqueness_of :boolean_attribute, if: :boolean_attribute
Just drop that in your model class. That will validate that the model has only one boolean_attribute set to true.
Note that you will have to work around the atomicity of swapping the boolean_attribute from one instance to another.
Depending on what database you are using you might be able to resolve it using a transaction. If your database doesn't support transactions you might have to figure out a better way to guarantee data consistency (such us having a dedicated model that points to the "active" model and removing boolean_attribute altogether, or replacing boolean_attribute with an integer that can be atomically incremented (highest number representing the active one).
A callback would probably be the best way. Something like :
before_create :check_boolean
def check_boolean
Model.find_by_boolean_value(true).nil? ? true : false
end
If check_boolean returns false, the create action is cancelled(instead of find_by you can also use exists?, which is probably a bit more clear coding)

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?

Resources