Ordering of relation based on associated table in rails4 - ruby

I have 2 models as below:
class Student < ActiveRecord::Base
has_many :marks
end
class Mark < ActiveRecord::Base
belongs_to :student
end
point is a field in marks table. For each student there are many entries in the marks table.
I need to get a list of students based on the order of highest total points.
I tried as below:
#students = Student.all.collect{|p| [p,p.marks.pluck(:point).sum]}
#students.sort_by { |h| h[1] }.reverse!
But it will return 2 items in each array, one the object and next the total points.
Is there a better solution please.
Thanks,
Jissy

This should do the trick:
Student.joins(:marks).select('students.*, SUM(marks.point) AS total_point').group(:id).order('total_point DESC')

You can do it like this.
Student.joins(:marks).select('id, sum(marks.point) as total_marks').group('students.id').order('total_marks desc')
If you are still unable to run it please modify it or let me know.In place of id in select you can select any column(s).

Related

How to get an array of values from a conditional ActiveRecord query with associations?

I'm looking to define a method on one of my objects that will return a just one column of data from all of its child objects so long as another column in the same record meets certain conditions.
For instance if I have two objects
ParentObject
has_many: child_objects
#fields
name (string)
ChildObject
belongs_to: parent_object
#fields
name (string)
whitelisted_at (datetime)
I've read up that I can get a list of all child_object records for a parent_object based on a conditional specified using .where(). For instance in my controller I have code like so:
ParentObject.child_objects.where("whitelisted_at IS NOT NULL")
This gives me an active record associate like so:
#<ActiveRecord::AssociationRelation [
<ChildObject id: 1, name:"Susan", whitelisted_at: "2015-02-18 12:07:37">,
<ChildObject id: 1, name:"Simon", whitelisted_at: "2015-02-18 12:07:37">,
<ChildObject id: 1, name:"Sally", whitelisted_at: "2015-02-18 12:07:37">
]
I was looking how I would then filter through these to return an array of just names. Ideally i'd be able to run this all as a Model method so:
class ChainObject < ActiveRecord::Base
...
def whitelisted_names
#... outputs [Susan, Simon, Sally]
end
end
What would be the most concise and rails-y way of doing this. I thought about doing a .where() then an .each() and having a block method but that seems really cumbersome and I'm sure I'm just missing some smart ActiveRecord or Association method that could pluck an array of values from multiple hashes. I'm pouring over the APIdock but I think the problem is I don't know how to describe what I'm trying to do!
In your parent model you could use where.not and use the pluck method ActiveRecord gives you (props to Stefan - see pluck)
class ParentObject < ActiveRecord::Base
...
def whitelisted_names
child_objects.where.not(whitelisted_at: nil).pluck(:name)
end
end

Ruby, iterate objects array in the right order

I have an array of objects and every object respond to the 'order' method.
I can write the method
objects = Objects.all
objects.each do |i|
puts i.order
end
but I'm not sure the order is correct. Is there any fast way to iterate my array following the right order of every object?
Update: real case.
class Articles < ActiveRecord::Base
as_many :article_pages
end
a = Article.find(2345)
pages = a.article_pages
pages.each ...
pages.first.order = 1
pages.last.order = 5
I need to iterate in my pages following order...
a.article_pages.order('order').each
doesn't work
By default, ActiveRecord will not guarantee any order. To change that, use:
a = Article.find(2345)
pages = a.article_pages.order('order asc')
to order by a column. Switch asc to desc to order in descending order.
You can use sort option in case you want it in ascending only
a = Article.find(2345)
pages = a.article_pages.all.sort_by &:order

Get unique objects on has_and_belongs_to_many

I have 3 entities: Feeds, Episodes, Series. Feeds has_and_belongs_to_many Episodes. Episodes belongs_to Series.
What I would like is all the series for a feed, and the number of episodes, in that series, in that feed.
You can produce the complete list of all series for a given set of episodes by first finding the IDs of all series...
# uniq insures that any duplicates are removed
ids = feed.episodes.map(&:series_id).uniq
And then finding the series themselves:
series = Series.where(id: ids)
You can find the number of episodes for each series with a simple count:
series.each do |s|
puts "Series #{s.name} has #{s.episodes.count} episodes"
end
meagar’s answer led me to the following solution:
ids = #feed.episodes.pluck(:series_id)
#series = Series.find(ids)
#episode_counts = Hash.new(0)
ids.each do |id|
#episode_counts[id] += 1
end

Inserting models at arbitrary positions in a rails 4 association collection

I have a typical has_many relation between two models, let's say Order and Item.
Also, I am using nested attributes like so:
class Order < ActiveRecord::Base
has_many :items
accepts_nested_attributes_for :items
end
When putting together a nested edit order form, I want to be able to build new items (where an item has a name and a quantity) and insert them at arbitrary positions within the previously saved list of items.
Suppose I have a sorted array of strings listing all_possible_item_names a customer can specify a quantity for.
Until rails 3.2.13, #order.items was a simple array, and I could use ruby's own Array#insert method to insert new items wherever I wanted:
# after loading the original order, this code will build additional items
# and insert them in the nested edit order form with a default qty of 0
all_possible_item_names.each_with_index do |name, pos|
unless #order.items.find { |i| i.name == name }
#order.items.insert pos, Item.new(name: name, qty: 0)
end
end
In rails 4, on the other hand, #order.items is a ActiveRecord::Associations::CollectionProxy, and insert has a different meaning.
How can I accomplish in rails 4 what I used to be able to do in rails 3?
Convert it into array then insert
#order.items.to_a.insert pos, Item.new(name: name, qty: 0)

Get distinct values of an has_many field

I have a model :
class Hotel < ActiveRecord::Base
has_many :hotel_comments
end
In my controller, i get some hotels:
#hotels = Hotel.all
How can I get all comments for my hotel dictionary?
Thank you!
Guessing what you mean by "dictionary":
Hash[Hotel.includes(:hotel_comments).map { |h| [h, h.hotel_comments] }]
If you just want all comments in a array:
Hotel.includes(:hotel_comments).map(&:hotel_comments).flatten(1)
Without seeing more of your model, I am also guessing a bit here too, but how about:
#biglist=new(array)
#hotels.for_each do |h|
sub_list=HotelComments.find_by_hotel_id(h.id)
#big_list.push(sub_list)
end
Or, if HotelComments is large, something like:
#biglist=new(array)
ids=new(array)
#hotels.for_each do |h|
ids.push(h.id)
end
#big_list=HotelComments.find_by_hotel_id(ids)
... would gather up the comments with one pass through HotelComments
You may find (much) better thoughts here: http://guides.rubyonrails.org/active_record_querying.html

Resources