So this below has always worked for me, but now I need to remove some of the items to get true cost and true sale price. I need to remove all items from this sum that has a parent_id of nil. How can I do this without making another sql query?
def total_price
# convert to array so it doesn't try to do sum on database directly
items.to_a.sum(&:full_price)
end
You can do
items.to_a.reject{|item|item.parent_id.nil?}.sum(&:full_price)
Use select/reject method on array.
Related
I have an array of objects in Rails for some table. I want to update its order field by the position of that object in the array with a single Active Record Query. How can I do that?
I have tried the update_all.(:"order" => ?) but couldn't get the object which is updating in update_all.
Suppose #user (only a reference you can use your corresponding object) is the array of objects (Activerecord) , then to update order field of all users in the array, you would have to run the following query
#user.update_all(order_field: value)
Suppose you have an array of posts, then you can do something like the following
posts.each_with_index do |post, index|
post.update_attributes order: index
end
This will execute a single query for each post. If you want a single query to update all the posts in the array, that is a lot harder to achieve. Options I can think of:
bulk updating
using a stored procedure
I am using Rails 5 and I want to delete an array of objects. In a previous thread, I read "destroy_all" was the truth and the light. I had two arrays of objects, which I subtract to get a third array
unused_currencies = all_currencies - currencies_from_feed
unused_currencies.destroy_all
but when using destroy_all I got this error:
NoMethodError: undefined method `destroy_all' for #<Array:0x007feea8878770>
This code will make a single SQL query:
unused_currencies = all_currencies - currencies_from_feed
CurrencyModel.delete(unused_currencies)
where CurrencyModel is the model of your currencies.
You might want to use destroy if you need to run callbacks on the models:
unused_currencies = all_currencies - currencies_from_feed
CurrencyModel.destroy(unused_currencies.map(&:id))
This code will make a number of queries proportional to the number of unused currencies
Destroy_all is for active-record type things.
What exactly are you trying to do? if you just want to get rid of the array, you can override it with
unused_currencies = []
If you're trying to destroy a bunch of active record objects in the array you're going to have to iterate over it and delete each object individually.
destroy_all works for the ActiveRecord::Relation
If you want to clear the array, you can do: unused_currencies = []
If you want to delete each item in the in the array:
unused_currencies.each(&:destroy). This will generate a delete query per item.
To delete all the objects at once (assuming they all belong to the same model. This will blow up in your face if they don't!)
unused_currencies.first.class.destroy_all(unused_currencies.map(&:id))
If you use map, you load in memory all data. I think you can just do:
all_currencies.where.not(id: currencies_from_feed.select(:id)).destroy_all
if all_currencies and currencies_from_feed are ActiveRecord::Relation, this will generate only one request sql.
Hi I'm working on a project and I have to get the sum of an attribute of a active record collection. So I used:
#total = #records.sum(:cost)
However this gives the wrong value, for example if I have:
#records.each{ |x| puts x.cost}
I get 118.80 and 108.00
but for #total I get 680.40, which obviously isn't the answer, however if I use:
#total = 0
#records.each{ |x| #total = #total + x.cost}
I get the right answer of 226.80
If anyone can help me understand what is going on here it would be greatly appreciated.
Be careful, as a record collection is an instance of ActiveRecord::Associations::CollectionProxy, not an Array. It means that if you call:
#object.collection.sum(:cost)
actually what gets called is this method: http://apidock.com/rails/v4.2.7/ActiveRecord/Calculations/sum
And it will call sum in the SQL database, so the result gets influenced by the parameters of the query, e.g. groups, joins, etc.
While if you want to use Array sum, as in here: http://apidock.com/rails/Enumerable/sum
You would have to make your object Array first, via to_a:
#object.collection.to_a.sum(&:cost)
try this:
pluck the values of attr cost into an array and aggregate their sum
#total = #records.pluck(:cost).sum
I have a massive table Foo from which I need to pluck all values in a certain field, Foo.who.
The array has millions of rows, but only a few thousand different values in the who column.
If the table was smaller of course I'd simply use Foo.pluck(:who)
If I use Foo.find_in_batches do |a_batch| each set is an Array of Foo records, rather than an activerecord collection of Foo records, so I cannot use .pluck() and AFAIK the only way to extract the who column is via something like .map(&:who) that iterates over the array.
Is there a way to pluck the who column from Foo in batches that does not require then iterating over each element of each batch to extract the who column?
In Rails 5 you can use:
Foo.in_batches do |relation|
values = relation.pluck(:id, :name, description)
...
end
Upd: for prevent memory leaks use:
Foo.uncached do
Foo.in_batches do |relation|
values = relation.pluck(:id, :name, description)
...
end
end
Here's a method to get the ids that were retrieved by the in_batches method itself, without need to run another query yourself.
in_batches already runs pluck(:id) under the hood (when load param is false which is the default) and yield the relation object. This relation object is created with where(id: ids_from_pluck).
Is it possible to get the list of ids directly from the relation object via where_values_hash method, without the need to run another query in DB. For example:
Foo.in_batches do |relation|
ids = relation.where_values_hash['id']
end
This should work on both Rails 5.x and 6.x, but it relies on implementation detail of in_batches so it is not guaranteed to work in future.
Try this:
Foo.select(:id, :who).find_in_batches do |a_batch|
...
end
I have #comments which is either 0 -XXXX number of comments from the DB.
I need this #comments as is as it is used in multiple places.
In one place I need #comments but minus the last record, if any.
How can I do that? w/o rehitting the db?
As already mentioned, #comments.pop will do the job. Another option is to use a range to select which items from the array to use:
#comments[0..-2]
how about popping off the last one using ruby, and returning a new array?
#comments.pop