Ruby-on-Rails: How to pull out most recent entries from a limited subset of a database table

偶尔善良 提交于 2019-12-13 02:17:38

问题


Imagine something like a model User who has many Friends, each of who has many Comments, where I'm trying to display to the user the latest 100 comments by his friends.

Is it possible to draw out the latest 100 in a single SQL query, or am I going to have to use Ruby application logic to parse a bigger list or make multiple queries?

I see two ways of going about this:

  1. starting at User.find and use some complex combination of :join and :limit. This method seems promising, but unfortunately, would return me users and not comments, and once I get those back, I'd have lots of models taking up memory (for each Friend and the User), lots of unnecessary fields being transferred (everything for the User, and everything about the name row for the Friends), and I'd still have to step through somehow to collect and sort all the comments in application logic.
  2. starting at the Comments and using some sort of find_by_sql, but I just can't seem to figure out what I'd need to put in. I don't know how you could have the necessary information to pass in with this to limit it to only looking at comments made by friends.

Edit: I'm having some difficult getting EmFi's solution to work, and would appreciate any insight anyone can provide.

Friends are a cyclic association through a join table.

has_many :friendships
has_many :friends, 
         :through => :friendships,
         :conditions => "status = #{Friendship::FULL}"

This is the error I'm getting in relevant part:

ERROR: column users.user_id does not exist

: SELECT "comments".* FROM "comments"  INNER JOIN "users" ON "comments".user_id = "users".id    WHERE (("users".user_id = 1) AND ((status = 2)))

When I just enter user.friends, and it works, this is the query it executes:

: SELECT "users".* FROM "users" INNER JOIN "friendships" ON "users".id = "friendships".friend_id WHERE (("friendships".user_id = 1) AND ((status = 2)))

So it seems like it's mangling the :through to have two :through's in one query.


回答1:


Given the following relationships:

class User < ActiveRecord::Base
  has_many :friends           
  has_many :comments

  has_many :friends_comments, :through => :friends, :source => :comments
end

This statement will execute a single SQL statement. Associations essentially create named scopes for you that aren't evaluated until the end of the chain.

@user.friends_comments.find(:limit => 100, :order => 'created_at DESC')

If this is a common query, the find can be simplified into its own scope.

class Comments < ActiveRecord::Base
  belongs_to :user

  #named_scope was renamed to scope in Rails 3.2. If you're working
  #if you're working in a previous version uncomment the following line.
  #named_scope :recent, :limit => 100, : order => 'created at DESC'
  scope :recent, :limit => 100, :order => 'created_at DESC'
end

So now you can do:

@user.friends_comments.recent

N.B.: The friends association on user may be a cyclical one through a join table, but that's not important to this solution. As long as friends is a working association on User, the preceding will work.



来源:https://stackoverflow.com/questions/2382642/ruby-on-rails-how-to-pull-out-most-recent-entries-from-a-limited-subset-of-a-da

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!