Select from multiple tables in Rails - Has Many "articles" through [table_1, table_2]?
I'm in a situation where I need to get all articles
that are tied to a User
through 2 tables:
- article_access: gives users privilege to see an article
- article_favorites: of public articles, users have favorited these
So in ActiveRecord you might have this:
class User < ActiveRecord::Base
has_many :article_access_tokens
has_many :article_favorites
def articles
unless @articles
ids = article_access_tokens.all(:select => "article_id").map(&:article_id) + article_favorites.all(:select => "article_id").map(&:article_id)
@articles = Article.send(:scoped, :conditions => {:id => ids.uniq})
end
@articles
end
end
That gives me basically an articles
asso开发者_运维技巧ciation which reads from two separate tables. Question is though, what's the right way to do this?
Can I somehow make 1 SQL SELECT call to do this?
yep, you could write a joins to do this, something like:
Article.all(:joins => "left join article_access_tokens on (article_access_tokens.article_id = articles.id and article_access_tokens.user_id = #{self.id})
left join article_favourites on (article_favourites.article_id = articles.id and article_favourites.user_id = #{self.id})",
:conditions => "article_favourites.id is not null or article_access_tokens.id is not null")
Needs to be a left join since an article could be in any or none of the two the tables (the conditions clause catches the case where it is in neither).
This may end up with duplicate results if you don't have a unique constraint on article_favourites article_id/user_id and article_access_tokens article_id/user_id, if that is the case, it is best to fix the data and add the unique constraint rather than doing a distinct.
For cleanliness, you could probably have a has_many :authorized_articles or a scope on the Article model which takes the user_id as the parameter.
精彩评论