【问题标题】:How do I dynamically chain where clauses in rails?如何动态链接rails中的where子句?
【发布时间】:2018-09-12 14:36:32
【问题描述】:

我有一个视频模型和一个标签模型。标签 HABTM 视频和视频 HABTM 标签。

class Tag < ApplicationRecord
  has_and_belongs_to_many :videos
  scope :with_tag, -> (id) { where(id: id) }
end

class Video < ApplicationRecord
  has_and_belongs_to_many :tags
end

我想知道如何创建一个查询,其中未知数量的标签会来自用户。所以我可以说,“给我看所有标有 (123 AND 124 AND 125) 的视频”。最终目标是我不知道用户要传入多少标签,所以我需要知道如何创建一个范围链并最终能够将整个内容传递到 ransack 上进行文本搜索结果视频的一些字段。我怎样才能做到这一点?

更新:我想知道如何使用 Rails 和 ActiveRecord 做到这一点。我知道如何使用 SQL 完成此任务。但是仅使用 SQL 完成它不会让我将结果关系传递给 ransack。

【问题讨论】:

  • 你在用postgresql吗?
  • 是的,我正在使用 postgres。
  • 你会存储来自用户的标签,对吧?
  • @EricLubow 这是最好的方法.. stackoverflow.com/a/11512925/2767755
  • @Pavan 它有一个连接表,作为 video_id 和 tag_id 存储在那里。

标签: ruby-on-rails has-and-belongs-to-many


【解决方案1】:

我创建了一些相关的表来编写这个答案,并根据表中的数据测试查询。所以,我在这里取帖子,标签 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

我得到了this answer 的帮助。

【讨论】:

  • 感谢您在此处包括范围。如果没有范围,以下.ransack() 调用将无法按我需要的方式工作。通过范围执行此操作,即使使用 SQL,它也使 .ransack() 调用工作。
  • @EricLubow 没问题.. 祝你好运! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-03-10
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 1970-01-01
  • 2011-01-31
  • 2021-10-20
相关资源
最近更新 更多