What is the most efficient way to delete an existing object from a Rails class? I have an array of objects
person_array = [Person1, Person2, Person3]
My goal is to delete all of the people in that array from a table in which they are members.
So I have a People class which they currently belong to.
I was thinking something like People.delete(person_array) which seems to be executing the proper SQL statements. How do I get those delete statements to actually change my People table though?
Since you already have the objects, you can just call destroy_all with them:
Person.destroy_all(:id => person_array)
Unlike delete_all, this will invoke the model's callbacks, which may take longer, but preserves integrity.
Not sure if you need to get the ids or Activerecord does that but for you.
Person.delete_all person_array.map(&:id)
Related
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
I have a model and can manually check every (:has_many, :has_one) dependency, but I want some magic like current_user.attributes for records. So when I update model, I don't need to update method.
I tried Reflections, but it returns all theoretical dependencies/connections of model, isn't it? And I need dependent records from DB.
Something like X.where(user_id: #user.id) or #user.dependents
Is it possible?
You can assign required object to model and then
model.class.reflect_on_all_associations.map { |table| model.method(table.name).call }.select(&:any?)
For example:
user = User.first
user.class.reflect_on_all_associations.map { |table| user.method(table.name).call }.select(&:any?)
# returns all associated objects of first user
You can specify result using :has_many, :has_one or :belongs_to as argument of reflect_on_all_associations.
Possibly there is more elegant way, but it works.
TL;DR Don't do this :)
You can do something quite similar using reflections. For example
#user.class.reflections.keys.flat_map { |reflection| me.send(reflection) }
will give you an array with all the objects associated with the user. But what's next?
For almost any real-world logic around this list's members (except the basics that come from AR::Base) you will have to check either a class of an object or use bug-prone try magic - both options are reasonable trade-off sometimes, but in most practical cases I'd prefer less smelly solutions (even if they are a bit more verbose).
I have a Invoice model which accepts_nested_attributes_for :line_items with allow_destroy: true. In my model, in a before_save callback, I can reference the data like this:
self.line_items
Some of the items will be deleted upon save. I want to be able to grab only the items that won't be deleted like this:
self.line_items.where(_destroy: false)
However, this obviously won't work since I am dealing with an unsaved object. So, my question is how do I get the list of items that won't be deleted? I know I could technically iterate through the list and add each applicable item to a new array, but I figure there is something more intuitive. For example, currently I use .sort_by(&:line_number) rather than the SQL .sort(:line_number) for sorting which allows me to sort in memory rather than from SQL. I need the same thing except for a .where clause.
Thanks in advance.
As far as I'm aware, where is aimed specifically at building SQL queries, so you can't use it to deal with in-memory criteria like whether something will be destroyed on save. For that, you can use the methods in the Enumerable module, which is included in the collection object. The sort_by call you mentioned is using that module. In this case, you'd probably use line_items.reject(&:marked_for_destruction?). See the documentation for marked_for_destruction? for more details.
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.
I've been wondering, suppose I have a model with an attribute that in every instance is dependent on that same attribute in other instances. The best example for this would be an order attribute for items in a list.
The best place to update the rest of the items' order attributes would be in a before_update callback method, were you have both the item's old and new values.
But now whenever you update the other items in the list the callback is going to be called again, and again...
I'm looking for an elegant way of solving this.
I have heard about the :update_without_callbacks method, but i don't want to use a private method, and also i feel like adding extra attributes would be unnecessary.
Got any good ideas? Thanks in advance!
One way would be to use update_all to set the order of all the other items in bulk.
That way you would efficiently limit the number of queries to one and prevent any callbacks from being triggered.
https://github.com/rails/rails/blob/83e42d52e37a33682fcac856330fd5d06e5a529c/activerecord/lib/active_record/relation.rb#L274
I feel the fact that you have to do this type of update across entries suggests you haven't properly conceptualized your problem. Why not create a List model that has the order attribute, and then create a one-to-many relationship between the List model and the Item model. This way, there's only one place to update the ordering information and no need for complicated and brittle callbacks.