【问题标题】:Combine multiple queries into one active record relation?将多个查询组合成一个活动记录关系?
【发布时间】:2015-04-11 17:02:04
【问题描述】:

我正在尝试为我的应用程序编写一个搜索查询,它将根据查询字符串搜索与该字符串匹配的组或用户。

这是我写的:

    def search_api
      @groups = Group.where("name ILIKE '#{params[:query]}'")
      @users = User.where("first_name ILIKE '#{params[:query]}' OR last_name ILIKE '#{params[:query]}")
    end

有没有办法将这两个查询组合成一个 activerecord 关系数组?除了对两个数组进行迭代并将它们合二为一的蛮力吗?

【问题讨论】:

  • 您将无法创建一个结合这两个结果的查询,除非组和用户通过单表继承位于同一个表中。这是因为它们将位于两个不同的表中,而 ActiveRecord 只允许您一次访问一个表(除非您使用联合编写自己的 SQL,但这无论如何都会使您远离 AR 结果,并且您无法加入您的方法)
  • @SharvyAhmed PG::SyntaxError: 错误: ":" 第一行或附近的语法错误: SELECT * FROM groups WHERE name ILIKE :query UNION SELECT * ...

标签: ruby-on-rails ruby-on-rails-4 activerecord


【解决方案1】:

我不确定解决方案,但我有一个安全建议。

您的查询不是 SQL 注入安全的。您可以传递数组而不是在 SQL 字符串中注入参数。

以下查询是 SQL 注入安全的:

@groups = Group.where("name ILIKE ?", "#{params[:query]}")
@users = User.where("first_name ILIKE ? OR last_name ILIKE ?", "#{params[:query]}")

【讨论】:

  • 谢谢,我会这样做的。出于好奇,这如何使它更安全?
  • 这里是供您参考的快速参考 - guides.rubyonrails.org/security.html(第 7 节)。当您传递数组而不是准备好的 SQL 语句时,activerecord 会在查询前清理参数。但是,当您通过语句时,它将按原样使用,无需任何清理。
  • ActiveRecord::StatementInvalid: PG::SyntaxError: ERROR: syntax error at or near ":" LINE 1: SELECT * FROM groups WHERE name ILIKE :query UNION SELECT * ...
  • Group.find_by_sql("SELECT * FROM groups WHERE name ILIKE ? UNION SELECT * FROM users WHERE first_name ILIKE ? OR last_name ILIKE ?", "#{params[:query]}")你能试试这个吗?
  • 也不喜欢那个。 ActiveRecord::StatementInvalid: PG::SyntaxError: ERROR: syntax error at or near "UNION"
【解决方案2】:

所以这里有一个解决方案。不确定它是否比保持原样更好,但正式它是问题的答案(除了结果不是 ActiveRecord 关系):

 Group.connection.execute("(SELECT id, 'groups' as table FROM groups WHERE...) UNION (SELECT id, 'users' as table FROM users WHERE...)")

这将返回一个 PG::Result 类型的对象,您可以将其视为哈希数组。而且,正如已经说过的,最好将参数作为数组传递,而不是将它们直接插入到 SQL 中。不幸的是,如果您想获得 ActiveRecord 的结果,您可以使用 UNION 仅用于对一个表的不同查询。在这种情况下,它看起来像:

 Group.find_by_sql("(SELECT * FROM groups WHERE...) UNION (SELECT * FROM groups WHERE...)")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多