I have posts which are sent by users to other users. There are two models - :post and :user, and :post has the following named开发者_Python百科 associations:
belongs_to :from_user, :class_name => "User", :foreign_key => "from_user_id"
belongs_to :to_user, :class_name => "User", :foreign_key => "to_user_id"
Both :user and :post have "is_public" column, indicating that either a single post and/or the entire user profile can be public or private.
My goal is to fetch a list of posts which are public AND whose recipients have public profiles. At the same time, I would like to "include" both sender and recipient info to minimize the # of db calls. The challenge is that I am effectively "including" the same table twice via the named associations, but in my "conditions" I need to make sure that I only filter by the recipient's "is_public" column.
I can't do the following because "conditions" does not accept an association name as a parameter:
Post.find(:all, :include => [ :to_user, :from_user ],
:conditions => { :is_public => true, :to_user => { :is_public => true }})
So, one way I can accomplish this is by doing an additional "join" on the "users" table:
Post.find(:all, :include => [ :to_user, :from_user ],
:joins => "inner join users toalias on posts.to_user_id = toalias.id",
:conditions => { :is_public => true, 'toalias.is_public' => true })
Is there a better, perhaps cleaner, way to do this?
Thanks in advance
I was facing the same problem and found a solution after watching sql query generated from rails query, sql query automatically generates an alias try this,
Post.find(:all, :include => [ :to_user, :from_user ],
:conditions => { :is_public => true, 'to_users_posts.is_public' => true })
It worked for me :)
I have not been able to find a better solution than the one originally stated in my question. This one doesn't depend on how Rails names/aliases tables when compiling a query and therefore appears to be cleaner than the alternatives (short of using 3rd party gems or plugins):
Post.find(:all, :include => [ :to_user, :from_user ],
:joins => "inner join users toalias on posts.to_user_id = toalias.id",
:conditions => { :is_public => true, 'toalias.is_public' => true })
If you are on Rails 3, take a look at squeel gem, esp if you are doing these kind of complex joins often. Or if you dont want to add a extra gem, take look at the Arel table in Rails 3.
I very pleasant for that question, because I've tried to find proper solution about 2h, so after using few tips above, I've found the proper, in my case, solution. My case: I need filter instances by created_by_id/updated_by_id fields, that fields are in every table, so...what I did In concern 'Filterable' I wrote the method and when I needed filter by that fields I used that ->
key = "#{key.pluralize}_#{name.pluralize.downcase}.email" if %w(created_by updated_by).include?(key)
# in case with invoices key = 'updated_bies_invoices.email'
results = results.eager_load(:created_by, :updated_by).where("#{key} = ?", value)
精彩评论