如何动态链接rails中的where子句?

我有一个video模型和一个标签模型。 标签HABTMvideo和videoHABTM标签。

class Tag  (id) { where(id: id) } end class Video < ApplicationRecord has_and_belongs_to_many :tags end 

我想知道如何创建一个查询,其中未知数量的标签将来自用户。 所以我可以说,“告诉我所有标有(123和124和125)的video”。 最终的目标是我不知道用户将传递多少标签,因此我需要知道如何创建一系列范围并最终能够将整个事物传递到hansack以进行文本搜索结果video的一些字段。 我怎么能做到这一点?

更新:我想知道如何使用Rails和ActiveRecord执行此操作。 我知道如何用SQL实现这一目标。 但仅使用SQL完成它将不允许我将结果关系传递给ransack。

我已经创建了一些相关的表来编写这个答案,并根据表中的数据测试查询。 所以,我在这里获取post,其中包含标签1和标签2。

在SQL中:

 rails-test_development=# select id from posts; id ---- 1 2 3 (3 rows) rails-test_development=# select id from tags; id ---- 2 3 4 5 6 (5 rows) rails-test_development=# select post_id, tag_id from posts_tags; post_id | tag_id ---------+-------- 1 | 2 2 | 3 2 | 2 2 | 1 3 | 1 3 | 2 1 | 4 (7 rows) rails-test_development=# WITH posts_tags_cte AS ( rails-test_development(# SELECT post_id, array_agg(tag_id) as tags rails-test_development(# FROM posts_tags rails-test_development(# WHERE tag_id in (1, 2) rails-test_development(# GROUP BY post_id rails-test_development(# ) rails-test_development-# SELECT posts.id FROM posts_tags_cte JOIN posts ON posts.id = posts_tags_cte.post_id rails-test_development-# WHERE posts_tags_cte.tags @> array[1, 2]::int8[]; id ---- 3 2 (2 rows) 

现在在Rails中:

 rails-test$ rails c Running via Spring preloader in process 7361 Loading development environment (Rails 5.2.1) 2.5.1 :001 > Post.by_tag([1,2]).first.attributes Post Load (1.7ms) SELECT "posts".* FROM (WITH posts_tags_cte AS ( SELECT post_id, array_agg(tag_id) as tags FROM posts_tags WHERE tag_id in (1,2) GROUP BY post_id ) SELECT posts.* FROM posts_tags_cte JOIN posts ON posts.id = posts_tags_cte.post_id WHERE posts_tags_cte.tags @> array[1,2]::int8[]) as posts ORDER BY "posts"."id" ASC LIMIT $1 [["LIMIT", 1]] => {"id"=>2, "name"=>"Postppp", "title"=>"Post", "content"=>"I don't know", "created_at"=>Sun, 09 Sep 2018 09:48:33 UTC +00:00, "updated_at"=>Sun, 09 Sep 2018 09:48:33 UTC +00:00, "month_and_year"=>Sun, 09 Sep 2018} 2.5.1 :002 > Post.by_tag([1,2]).last.attributes Post Load (1.3ms) SELECT "posts".* FROM (WITH posts_tags_cte AS ( SELECT post_id, array_agg(tag_id) as tags FROM posts_tags WHERE tag_id in (1,2) GROUP BY post_id ) SELECT posts.* FROM posts_tags_cte JOIN posts ON posts.id = posts_tags_cte.post_id WHERE posts_tags_cte.tags @> array[1,2]::int8[]) as posts ORDER BY "posts"."id" DESC LIMIT $1 [["LIMIT", 1]] => {"id"=>3, "name"=>"Post A", "title"=>"Post title", "content"=>"Lorem Ipsum is simply dummy text of the printing and typesetting industry.", "created_at"=>Sun, 09 Sep 2018 09:52:57 UTC +00:00, "updated_at"=>Sun, 09 Sep 2018 09:52:57 UTC +00:00, "month_and_year"=>Sun, 09 Sep 2018} 2.5.1 :003 > 

我将范围定义为:

 class Post < ApplicationRecord has_and_belongs_to_many :tags scope :by_tag, -> (tag_ids) { sql = sanitize_sql_array [<<-SQL, tag_ids, tag_ids] (WITH posts_tags_cte AS ( SELECT post_id, array_agg(tag_id) as tags FROM posts_tags WHERE tag_id in (?) GROUP BY post_id ) SELECT posts.* FROM posts_tags_cte JOIN posts ON posts.id = posts_tags_cte.post_id WHERE posts_tags_cte.tags @> array[?]::int8[]) as posts SQL from(sql) } end 

我从这个答案中得到了帮助。