Get specific column from a collection ActiveRecord objects? - ruby-on-rails

How can I extract a list of IDs from a returned ActiveRecord results without re-querying the ID column alone?
For exmaple:
people = People.all
people.get_ids #Returns an array of IDS
My current solution is to loop through people and get the ID manually(which isn't very elegant, IMHO)

You can use pluck method:
e.g. People.pluck(:id)
Refer http://apidock.com/rails/ActiveRecord/Calculations/pluck
Fetching using pluck would be better compared to the process of fetching the same after taking all results.
Hope that helps..

You can use map method
all_ids = people.map(&:id) #[1,2,3,4]

ids = People.all.map(&:id)
This code will return array of ids

Related

How to query to return the most common foreign key in a join table with rails

I have 3 models. Project, ProjectMaterial, and Material
A Project has_many ProjectMaterials and many Materials through ProjectMaterials.
This is bidirectional, with ProjectMaterial acting as a join table with user-submittable attributes.
I'd like to query the ProjectMaterial model to find the most frequent value of material_id. This way I can use it to find the most frequently used material.
Any help with a query would be greatly appreciated. I'm stuck. Thanks in advance!
You can chain group, count and sort methods on your ActiveRecord query like this:
ProjectMaterial.group(:material_id).count.values.sort.last
The first part ProjectMaterial.group(:material_id).count gives you the hash of each {material_id0 => rows_count0, material_id1 => rows_count1, ...}. Then, you can just get the values of the hash in an array, sort it and get the last item.
One way could be pluck ids to get the array, then count the most frequent.
ids = ProjectMaterial.pluck[:material_id]
For example: Ruby: How to find item in array which has the most occurrences?
Or better, by query to get a hash with counts:
counts = ProjectMaterial.group(:material_id).count
Once you know that you get a hash, you can sort by any ruby method, picking the most frequent or the n most frequent. Example of sorting:
counts.sort_by { |_, v| v }

In Rails, how do I delete all the objects in an array?

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.

Summing 5 objects after a where statement

I have an active record of 5 objects as follows
#top_sold = Photo.where(photographer_id: #photog).order('qty_sold DESC').first(5)
I want to know the sum of qty_sold for all 5 photos
This isnt working
#top_sold.sum(:qty_sold)
Much thanks in adcance
.first returns Array, use limit instead (which returns ActiveRecord::Relation).
#top_sold = Photo.where(photographer_id: #photog).order('qty_sold DESC').limit(5)
for Array you can do
#top_sold.map(:qty_sold).inject(:+)
Have you tried appending sum to your query?
#top_sold = Photo.where(photographer_id: #photog)
.order('qty_sold DESC').first(5).sum('qty_old')
If you need the original result set, then #Nithin answer is what you want to do.

Sort unordered SQL results based on the original Array order

I send an Array of IDs into a controller params[:ids] = [2,5,9,...]
Now if I perform a Query like Device.find(params[:ids]) the results are sorted based on the Database. How can I sort the result based on the original Array, so the Device with the id 2 comes first etc.?
You could look up the id's index with Array#index:
ids = params[:ids]
Device.find(ids).sort_by { |device| ids.index(device.id) }
You can do it just by using SQL:
Device.where(params[:ids]).order("field(id, #{params[:ids].map(:to_i).join(',')})")
This will be faster than doing it with Ruby.

Modifying the returned value of find_by_sql

So I am pulling my hair over this issue / gotcha. Basically I used find_by_sql to fetch data from my database. I did this because the query has lots of columns and table joins and I think using ActiveRecord and associations will slow it down.
I managed to pull the data and now I wanted to modify returned values. I did this by looping through the result ,for example.
a = Project.find_by_sql("SELECT mycolumn, mycolumn2 FROM my_table").each do |project|
project['mycolumn'] = project['mycolumn'].split('_').first
end
What I found out is that project['mycolumn'] was not changed at all.
So my question:
Does find_by_sql return an array Hashes?
Is it possible to modify the value of one of the attributes of hash as stated above?
Here is the code : http://pastie.org/4213454 . If you can have a look at summarize_roles2() that's where the action is taking place.
Thank you. Im using Rails 2.1.1 and Ruby 1.8. I can't really upgrade because of legacy codes.
Just change the method above to access the values, print value of project and you can clearly check the object property.
The results will be returned as an array with columns requested encapsulated as attributes of the model you call this method from.If you call Product.find_by_sql then the results will be returned in a Product object with the attributes you specified in the SQL query.
If you call a complicated SQL query which spans multiple tables the columns specified by the SELECT will be attributes of the model, whether or not they are columns of the corresponding table.
Post.find_by_sql "SELECT p.title, c.author FROM posts p, comments c WHERE p.id = c.post_id"
> [#<Post:0x36bff9c #attributes={"title"=>"Ruby Meetup", "first_name"=>"Quentin"}>, ...]
Source: http://api.rubyonrails.org/v2.3.8/
Have you tried
a = Project.find_by_sql("SELECT mycolumn, mycolumn2 FROM my_table").each do |project|
project['mycolumn'] = project['mycolumn'].split('_').first
project.save
end

Resources