Rails 3 many to many query condition

空扰寡人 提交于 2019-12-02 01:42:56

I don't know if it will solve you problem but for complex queries like that I almost always just use Squeel.

Then do something like this:

@posts = Post.joins(:tags)
  .where{tags.name.like_any names_array}
  .group("post_id")
  .having("count(post_id) = #{names_array.size}")

The SQL hopefully looks something like this

SELECT "posts".* FROM "posts"
  INNER JOIN "tags" ON "tags"."post_id" = "posts"."id"
  WHERE (("tags"."name" LIKE "TagA" OR "tags"."name" LIKE "TagB"))
  GROUP BY post_id
  HAVING count(post_id) = 2

If I remember squeel is pretty good at using ILIKE instead of LIKE depending on the database used. (atleast better than AR)

Also you could do this using AR without squeel but I REALLY like some of the ideas and helpers that come with squeel like _all


As for an explination...

Assume I searched for TagsA and B.

What that does is finds all the Posts with those tags.

So you'll have something like:

  • PostA TagA
  • PostA TagB
  • PostB TagA
  • PostB TagB
  • PostC TagA

Then it will group all those different Post results by the joined tags using post_id.

  • PostA TagA TagB
  • PostB TagA TagB
  • PostC TagA

Then it will check the number of Tags the SQL line has by checking how many forgien_ids are present. Since A and B have 2 tags you know it matched all you input.

Ok so I found no way to avoid a find_by_sql. Here is what I've done.

@posts = Post.find_by_sql([ "SELECT * FROM posts p
    JOIN (
        SELECT pt.post_id FROM posts_tags pt
        JOIN posts p ON p.id = pt.post_id
        JOIN tags t ON t.id = pt.tag_id
        WHERE t.label IN (?)
        GROUP BY pt.post_id
        HAVING count(pt.post_id) = ?
    ) ct ON c.id = ct.post_id", names_array, names_array.size])

I personally don't completely understand this query (found on http://www.sergiy.ca/how-to-write-many-to-many-search-queries-in-mysql-and-hibernate/ - #3). Especially the part where it joins a select. So if anyone could explain how really work this query it would be great.

Further more, if anyone knows how to do this in a more "rails" way (than a hard coded query), I'd love it.

Hope this helps some people.

hershey

I'm stuck on the same problem. The squeel docuemtnation suggests this is possible. In the Compound Conditions section he lists three ways to do something similar.

Given

names = ['Ernie%', 'Joe%', 'Mary%']

Then you can do

Person.where('name LIKE ? OR name LIKE ? OR name LIKE ?', *names)

or

Person.where((['name LIKE ?'] * names.size).join(' OR '), *names)

or

Person.where{name.like_any names}

The documentation implies we can use AND instead of OR or like_all as opposed to like_any.

However I can't seem to get it to work for a habtm relationship. It keeps giving me undefined method 'call' for an instance of ActiveRecord.

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