Question

I want the equivalent of SO search by tag, so I need an exists query but I also still need to left join on all tags. I've tried a couple of approaches and I'm out of ideas.

The Qustion - Tag relationship is through has_and_belongs_to_many both ways (i.e. I have a QuestionTags joiner table)

e.g.

Question.join(:tags).where('tag.name = ?', tag_name).includes(:tags)

I would expect this to do what I need but actually it just mashes up the includes with the join and I just end up with basically an inner join.

Question.includes(:tags)
   .where("exists (
               select 1 from questions_tags 
                where question_id = questions.id 
                  and tag_id = (select id 
                                  from tags 
                                 where tags.name = ?))", tag_name) 

This fetches the correct results but a) is really ugly and b) gives a deprecation warning as again it seems to confuse the includes with the join:

DEPRECATION WARNING: It looks like you are eager loading table(s) (one of: questions, tags) that are referenced in a string SQL sn ippet. For example:

Post.includes(:comments).where("comments.title = 'foo'")

Note I'm trying to write these as named scopes.

Let me know if the question isn't clear. Thanks in advance.

Était-ce utile?

La solution

OK, got it. I know no built in syntax to do it. I have used an alternative before, You can do like this:

Question.include(:tags).where("questions.id IN (
#{ Question.joins(:tags).where('tags.name = ?', tag_name).select('questions.id').to_sql})")

You can also join this subquery to your questions table instead of using IN. Alternatively if You are not against adding gems and You are using Postgres, use this gem. It provides really neat syntax for advanced queries.

Autres conseils

Use preload instead of includes:

Question.preload(:tags).where("exists ....

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top