How to query .where on array of clients? - ruby-on-rails

Using Rails 5.
I have an ordered array of clients. It's not possible for me to get an AR out of it, and this is the only way I can get these clients.
And I want to show only the clients where a certain condition is met. .where(category_id: 1), but as this is not an AR, I can't run a .where(category_id: 1) on the array of clients.
How do I achieve this? With a Scope? But how specifically? And is this still used in Rails 5?
I am basically in the same situation as second-most-upvoted in this question and basically I have an array with my clients:
ActiveRecord.find(array_of_ids), preserving order (Couldn't make the other suggestions work in the thread about turning my array into an AR)
Anyways, how can I achieve this?

I would iterate through the array and save the values in a variable that can be accessed by .where(category_id: )
array = [1,2,3,4,5,6,7]
array.each do |a|
if xyz.where("category_id (?)", a) == true
do something here
end
end
So something like xyz.where("category_id (?)", a)should be possible now.

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 }

How do I count items in an array that have a specific attribute value?

In my application, I have an array named #apps which is loaded by ActiveRecord with a record containing the app's name, environment, etc.
I am currently using #apps.count to get the number of apps in the array, but I am having trouble counting the number of applications in the array where the environment = 0.
I tried #apps.count(0) but that didn't work since there are multiple fields for each record.
I also tried something like #apps.count{ |environment| environment = 0} but nothing happened.
Any suggestions?
Just use select to narrow down to what you want:
#apps.select {|a| a.environment == 0}.count
However, if this is based on ActiveRecord, you'd be better off just making your initial query limit it unless of course you need all of the records and are just filtering them in different ways for different purposes.
I'll assume your model is call App since you are putting them in #apps:
App.where(environment: 0).count
You have the variable wrong. Also, you have assignment instead of comparison.
#apps.count{|app| app.environment == 0}
or
#apps.count{|app| app.environment.zero?}
I would use reduce OR each_with_object here:
reduce docs:
#apps.reduce(Hash.new(0)) do |counts, app|
counts[app.environment] += 1
counts
end
each_with_object docs:
#apps.each_with_object(Hash.new(0)) do |app, counts|
counts[app.environment] += 1
end
If you are able to query, use sql
App.group(:environment).count will return a hash with keys as environment and values as the count.

performing activerecord query on manualy created array of models

In Rails 3 I can perform query on associated models:
EXAMPLE 1:
model.associated_models.where(:attribute => 1)
associated_models is an array of models.
Is it possible to perform activerecord query on manualy created array of models?
EXAMPLE 2:
[Model.create!(attribute: 1), Model.create!(attribute: 2)].where(:attribute => 1)
Just like associated_models in first example its and array of models, but I guess there is something going on backstage when calling associated_models.
Can I simmulate this behaviour to get example 2 working?
short answer is no, you cannot. Activerecord scope chains construct queries for the db and this cannot be interpreted for arbitrary arrays, even if it is array of AR objects like in your example.
You can 'simulate' it by either a proper db scope
Model.where(:id => array_of_ar_objects.map(&:id), :attribute => 1)
(but this is wrong, since you want to do db calls only if needed) or by using array search:
array_of_ar_objects.select { |model| model.attribute == 1 }
Also note that model.associated_models is not an Array, but a ActiveRecord::Associations::HasManyAssociation, a kind of association proxy. It is quite tricky cause even its 'class' method is delegated to the array it is coerced to, this is why you were misled I guess.
model.associated_models.class == Array
-> true
I'd recommend Array#keep_if for this task rather than, squeezing an array into an an ActiveRecord::Relation.
[Model.create!(attribute: 1), Model.create!(attribute: 2)].keep_if { |m| m.attribute == 1 }
http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-keep_if
(Note, Array#select! does the same thing, but I prefer keep_if to avoid confusion when reading it later, thinking that it might be related to an sql select)

Does ActiveRecord find_all_by_X preserve order? If not, what should be used instead?

Suppose I have a non-empty array ids of Thing object ids and I want to find the corresponding objects using things = Thing.find_all_by_id(ids). My impression is that things will not necessarily have an ordering analogous to that of ids.
Is my impression correct?
If so, what can I used instead of find_all_by_id that preserves order and doesn't hit the database unnecessarily many times?
Yes
Use Array#sort
Check it out:
Thing.where(:id => ids).sort! {|a, b| ids.index(a.id) <=> ids.index(b.id)}
where(:id => ids) will generate a query using an IN(). Then the sort! method will iterate through the query results and compare the positions of the id's in the ids array.
#tybro0103's answer will work, but gets inefficient for a large N of ids. In particular, Array#index is linear in N. Hashing works better for large N, as in
by_id = Hash[Thing.where(:id => ids).map{|thing| [thing.id, thing]}]
ids.map{|i| by_id[i]}
You can even use this technique to arbitrarily sort by any not-necessarily unique attribute, as in
by_att = Thing.where(:att => atts).group_by(&:att)
atts.flat_map{|a| by_att[a]}
find_all_by_id is deprecated in rails 4, which is why I use where here, but the behavior is the same.

How to get array with clear data from Active Record query without using map

Hi I would like to ask if its possible get array with clear data from ActiveRecord query without using map, collect or each.
names = User.find(:all, :select => "name")
return names == [#<User name:"Peter">,#<User name:"Martin">]
and I want names == ["Peter", "Martin"] without using map, collect or each. Thanks for your answers.
User.connection.select_values("SELECT name FROM users")
#=> ["francois"]
Even if ActiveRecord provided a method to do what you want (single column to array of values), it would internally use a loop (each or collect) to do it.
I don't see what is so wrong with using a loop in this case, Ruby makes it quite easy to do it.
users = User.find(:all, :select => "name").collect { |u| u.name }
No you can't do that w/o using map, collect each ... etc......
In otherwords you can't get result like this in a single query.

Resources