How to get highest count of associated model (Rails)? - ruby-on-rails

A User has_many Solutions
How do I order Users by those with the most Solutions?
I'm trying to find the top ten users but I'm not sure how the most tidy or efficient way to do this?
Does anyone have an example that isn't too computationally expensive?

User
.joins(:solutions)
.select("users.*, count(solutions.id) as scount")
.group("users.id")
.order("scount DESC")

If you really want a fast way of doing it, put a counter_cache on a users' solutions (have a solutions_count column in your User) and order by that column. You don't need to manage that counter, because rails does it for you. You can read more about counter_cache in the Rails Guides

Assuming the following models
class User
has_many :solutions
end
class Solution
belongs_to :user
end
Then the best way is to counter_cache the solutions_count and order by it. more on counter_cache
The query will then be
User.order("users.solutions_count DESC").limit(10)
Don't forget to index the solutions_count column.

Related

Rails - How to query records in 5 different tables by user_id

I have models UserVote, Comment, Edit, etc, all of which have a user_id attribute. I'm trying to create a sort of timeline of recent activity, and this has me querying all 5 of my models separately and sorting by datetime. However, with accounts that have a lot of activity, these 5 queries take a very long time to execute. I'd like to find a way to optimize the performance, and I figured combining the 5 queries might work.
I haven't been able to come up with any working query to achieve what I'd like.
Thanks for any help!
I think the best suggestion in the comments is from Steve Jorgensen, with "I have generally seen this done by adding records to an activity log, and then querying that.".
If you want to take this idea to the next level, check out sphinx (a search engine designed for indexing database content). You can integrate easily with rails using thinksphinx - http://freelancing-god.github.com/ts/en/.
Also, as Tim Peters brings up, you really should have indexs on all of your fkeys, regardless of how you solve this - http://apidock.com/rails/ActiveRecord/ConnectionAdapters/SchemaStatements/add_index.
I think it is good idea to use Polymorphic associations for this problem - http://guides.rubyonrails.org/association_basics.html#polymorphic-associations
class TimeLine < ActiveRecord::Base
belongs_to :timelineable, :polymorphic => true
end
class UserVote < ActiveRecord::Base
has_many :time_lines, :as => :timelineable
end
class Comments < ActiveRecord::Base
has_many :time_lines, :as => :timelineable
end
Now you can sort time_line and access associated resources.

rails 3.1: how do activerecord query through series of 3 tables joined by has_one?

User has_one UserProfile which has_one Community.
Given a community_id, I want a list of emails from the Users table.
How do I get a list of all User.email where community_id = 5?
The best I can find (which does work) is:
User.select(:email).joins(:user_profile).merge(UserProfile.for_community(5))
But it seems brute-force... is there not a way to do something simpler along the lines of this below?
User.user_profile.community(5)
I don't think you know what your code does...
If the UserProfile has_one community, then the communities table must have a column titled user_id. That means there is only one User associated with any given community id.
To solve your question, as stated, you could delegate the user method to the user_profile.
class Community < ActiveRecord::Base
belongs_to :user_profile
delegate :user, to: :user_profile
end
Then you could do Community.find(community_id).user.email
Hope that helps.
I think going from the other direction might accomplish what you're looking for:
Community.find("5").user_profile.user.emails

Rails 3: Fastest way to determine model popularity by counting association

Suppose I have a Post model which has_many Comments. I want to get the top 10 most popular posts based on those who have the most comments. Assuming I have hundreds of thousands of posts, what's the most efficient way of getting those 10 top posts?
Also, how do I cache that query?
Thanks!
I'd suggest you add a counter-cache column on Post called comments_count. Add an index on this column, and then you can select the most popular posts by:
# app/models/post.rb
scope :popular, lambda { order("comments_count DESC").limit(10) }
Check out the ActiveRecord associations class methods document for more info on counter-caches.

DRY way to add same condition on many queries

I use rails 3.0.5
I've User and Company models, a user belongs_to a Company.
The Product, Bill, a several others also belongs_to a Company.
For obvious reasons, a User can acts on a Product, Bill... only if the Product's Company is the same as the User's Company.
I can use custom scope queries adding the condition on the company for everything, but it's not DRY at all.
How would you do that the the nice way?
Thanks
#product = current_user.company.products.find params[:id]
should work. If you want to DRY it up further I'd recommend using the plugin InheritedResources which has a sweet method called begin_of_association_chain (see in the README under overwriting defaults) that let's you define this stuff globally.
Have you looked into named scopes? http://api.rubyonrails.org/classes/ActiveRecord/NamedScope/ClassMethods.html
Seems like exactly what you are looking for
You can define a association
has_many :products, :through => :company
Then you can do
user.products.find(params[:id])
Not sure if this is the right way to do it!!!

Access join table data in rails :through associations

I have three tables/models. User, Alliance and Alliance_Membership. The latter is a join table describing the :Alliance has_many :Users through :Alliance_Membership relationship. (:user has one :alliance)
Everything works ok, but Alliance_Membership now has an extra field called 'rank'. I was thinking of the best way to access this little piece of information (the rank).
It seems that when i do "alliance.users", where alliance is the user's current alliance object, i get all the users information, but i do not get the rank as well. I only get the attributes of the user model. Now, i can create a helper or function like getUserRole to do this for me based on the user, but i feel that there is a better way that better works with the Active Record associations. Is there really a better way ?
Thanx for reading :)
Your associations are all wrong - they shouldn't have capital letters. These are the rules, as seen in my other answer where i told you how to set this up yesterday :)
Class names: Always camelcase like AllianceMembership (NOT Alliance_Membership!)
table names, variable names, methods and associations: always underscored and lower case:
has_many :users, :through => :alliance_memberships
To find the rank for a given user of a given alliance (held in #alliance and #user), do
#membership = #alliance.alliance_memberships.find_by_user_id(#user.id)
You could indeed wrap this in a method of alliance:
def rank_for_user(user)
self.alliance_memberships.find_by_user_id(user.id).rank
end

Resources