Equivalent of .where without Query in before_save - Rails - ruby-on-rails

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.

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

Prevent sql update on existing Rails model when appending to has_many relationship

According to the present Rails documentation, regarding the << operator on a has_many relationship on an existing object:
collection<<(object, …)
Adds one or more objects to the collection by setting their foreign keys
to the collection’s primary key.
(This is the interesting bit)
Note that this operation instantly fires update sql without waiting for
the save or update call on the parent object.
I didn't realize this would happen, I was quite surprised; I could have sworn this was not the case in the past, though I admit I could be wrong.
In either case, I haven't been able to find any additional documentation regarding this, however I wonder if there is a way to prevent this update?
My situation is simple, I merely have an object which exists in the database, which is being prepared for an "edit" page. I append one or multiple related objects before the page is render. C'est tout.
Update:
Apparently the same update-scenario also occurs if you set the has_many relationship directly from an array using the = operator.
Use the collection's build method. That won't immediately fire a SQL statement like the others do.
foo.bars.build(attributes)
foo.save
Lots of good information can be found here: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
Note: This method assumes you have the flexibility to create your objects through the build method rather than using Bar.new.

Order by association field using ActiveRecord

Is it possible to write an ActiveRecord query that sorts by an association field if the association exists, and otherwise sorts by an attribute on the object itself?
Example: I have a Discussion object which has_many :comments. I'd like to display a list of discussions sorted by discussion.latest_comment.created_at. However, some discussions may not have any comments, in which case I would like use their discussion.created_at attribute instead.
The catch is that I need the result to be an ActiveRecord::Relation (for performance reasons, and also because we are using Kaminari [which requires a Relation object]).
The only thing I could think of is to actually create a new field like discussion.latest_comment_at which would be initially populated by discussion.created_at and then updated every time a new comment is posted. However, this doesn't seem very straight-forward from a maintenance perspective (e.g. what happens when a comment gets deleted?).
I don't know of a way to do this through SQL, so I cheated and I have my code set a last_post_at attribute whenever a topic is created.
That way, I can then sort the topics by last_post_at rather than having to query two tables at once.
I've seen other forum systems do it this way too, and it seems like what you're designing is exactly a forum-like system.

Deleting saved objects from a class Ruby

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)

updating a model while in before_update

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.

Resources