Saving record fails due to uniqueness conflict with itself? - ruby-on-rails

I have a procedure which receives two models, one which already exists, and another one which holds new attributes which I want to merge in the first one.
Since other parts of the program are holding the same reference to the new model, I can't just operate on the existing one. Therefor I do the following:
def merge(new_model, existing_model)
new_model.attributes = existing_model.attributes.merge(new_model.attributes)
new_model.id = existing_model.id
end
Now the new_model is being saved which gives me the uniqueness erorr (even though it's technically the same model). I also tried using the reload method, but that yields the same result.
Background:
The method above is run in a before_add callback on an association. I want to be able to call update on a model (with nested associations) without having to specify IDs of the nested models. This update is supposed to merge some associations, which is why I try to do the whole merge thing above.

You can't set the id of a model and then save the record expecting the id to be set since the id is the primary key of the database. So you are actually creating a whole new record and, thus, the uniqueness validation error. So you'll need to think of some other design to accomplish what you are wanting. It may help to know that what you are trying to do sounds similar to a deep_dup, except that ActiveRecord doesn't define this method (but Hash does).

Related

access ActiveRecord Has Many associations

I have a model which has a lot of associations. What I need to do is to check whether one of those associations is not present or all of them are set correctly.
To do so, I created an array which includes all of those needs-to-be-checked fields. And created a loop through each element, but the case is that I can not access has_many related attributes with read_attribute method. It basically returns nil whenever I try to access has many associated fields.
What I am trying to do, I can access all related objects via car.drivers but I can not access the same object with car.read_attribute(:drivers) (because some of them are attributes and some are relations)
I think it's the behavior of read_attribute, so what should I use to access any (attribute or relation) on ActiveRecord object?
Regarding to the comments, it looks like no one understand what I am trying to do. I want to access the relations of one ActiveRecord object such like;
RELATIONS.each do |relation|
puts "#{relation} exists" if #object.relation.present?
end
What I do not know about this, is there any method that I can access the related objects with their string typed name. Similar to, #object.read_attribute(:attribute_name) In that way I can create a for loop, but for relations not for the attributes
To do so, I used dynamical method call. Below is an example of showing it
RELATIONS.each do |relation|
puts "#{relation} exists" unless #object.send('relation').nil?
end

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.

Rails validations: update at the same time as creation

I'm having some trouble trying to figure out how to order ActiveRecord writes to make my validations be happy, and I'm not sure what to search for this kind of problem.
The problem is that before the request would occur, everything would be valid; after the transformations would occur, everything would be valid again; but while the transformation is happening, since it's impacting more than one model instance, the database would enter an invalid state if I update each model one by one without taking into account both changes at the same time. I'd love some suggestions!
Background
I have a model called HelpRequest and another called HelperAssignments.
The rule is that a HelpRequest may have 0 or 1 active HelperAssignments. But if a Helper cannot complete the request, they may reassign it to another Helper, creating a new HelperAssignment. Since we need the history of assignments to a particular HelpRequest, there may be a number of HelperAssignments for a HelpRequest, but only one is active.
As a result, the HelperAssignment table has a few relevant attributes:
help_request_id: Refers to the HelpRequest corresponding to this assignment.
close_status: If this is set to reassigned, reassignment_id must be present.
reassignment_id: For a given help_request_id, only one may be nil (i.e. it is the current active assignment)
Problem
When a reassignment happens...
... if I create the new HelperAssignment first, it would break validations because more than one active HelperAssignment for the request would be present :(
... if I update the old HelperAssignment first to have a close_status of reassigned, the new HelperAssignment wouldn't exist yet so I couldn't get its ID, and therefore the validations would fail.
Is there an idiomatic way to do this transformation? I'd like to avoid a) disabling validations for this particular type of requests, or b) adding an extra database state for "being in the process of reassigning". Looks like enforcing referential integrity in models can get a little tricky in Rails... thanks in advance!

what is the difference between an object_id, and id?

for any model instance, there is an #object_id and #id - I know that they are not the same.
However, I'm not quite sure what makes them different and how they would each be used in context.
Please help clear this up!!
Thanks!
In Rails, an ActiveRecord model instance has an id property that maps to the value stored in the id column of the database. This may be nil if the record hasn't been saved.
In Ruby, object_id is a value that represents the identity of the object in question. It is always populated with something since everything in Ruby is an object.
These two are not related. There may be several independent instances of a model, each with their own object_id value but an identical id.
If two variables refer to something with the same object_id, then they refer to exactly the same object.
It's rare to see object_id used in code, it's a Ruby internal that's hardly ever needed. Mostly it's to establish if you're talking about identical objects, or just equivalent ones.
You will, on the other hand, see id and similar values used frequently since that's the glue that holds your relational database together.
Everything (and i mean everything) in Ruby is an object. Each of these objects has an object_id, which is a value used to track them in memory, basically.
In Rails, model instances are automatically set up with methods to return their value from the corresponding column in the database. .id is one of these.
As far as using in context, generally you would not use object_id in your code, ever: it's an under-the-hood thing.
EDIT - as an aside, a common issue seen in older versions of ruby/rails (where the object_id method was actually called id, and was overridden by rail's id method) was caused by the fact that the object_id of nil is 4. So you would call id on a variable which you expected to be a model instance, but was actually nil, thus getting "4" back when you expected to get the id of a record from the database.
In short, :id is the default primary_key of a table.And object_id could be the foriegn_key unless you set a custom foreign_key.
For example,take these two table users and posts.The relation would be
user => has_many posts and
post => belongs to user
so in the posts table,we should create a foreign_key(in this case user_id) to make the relations works.
Hope it helps!
id is specific for ActiveModel record and it relates to id column in database. object_id is defined on Object and is unique for every single object created in the memory.

How Should a has-many Association Behave When A Record That is Already Present Is Added?

I'm trying to work through a more complex issue, but I can't seem to find a definitive answer regarding the way has_many handles situations where an object already present in the association is added again.
What is the expected behaviour in the following situation (where alpha has many betas:
alpha.betas << beta_1
alpha.betas << beta_1
Should the second insertion be silently ignored (ensuring only unique betas in alpha's association?)
The docs state the following:
collection<<(object, …)
Adds one or more objects to the collection by setting their foreign keys to the collection's primary key. Note that this operation instantly fires update sql without waiting for the save or update call on the parent object, unless the parent object is a new record.
So my understanding is, that the object is referenced only once. It is therefor only once in the active_record relation alpha.betas. If you call it again, the foreign_key is set again, to the same value it already has. So this changes nothing.

Resources