【问题标题】:Parameterize an ActiveRecord #joins method参数化 ActiveRecord #joins 方法
【发布时间】:2019-07-03 23:28:38
【问题描述】:

我正在重构一个相当复杂的查询,该查询涉及将多个 .joins 方法链接在一起。在其中一个连接中,我使用了一个使用字符串插值的原始 SQL 查询,即连接 WHERE foo.id = #{id}。我知道我可以通过使用 ? 变量并将参数作为参数传递来参数化 ActiveRecord #where,但是 joins 方法不支持这种方式的多个参数。例如:

使用:

Post.my_scope_name.joins("LEFT JOIN posts ON posts.id = images.post_id and posts.id = ?", "1") 以传递 1 的 id 会产生 ActiveRecord::StatementInvalid

因为生成的 SQL 看起来像这样:

"LEFT JOIN posts ON posts.id = images.post_id and posts.id = ? 1"

使用joins 方法时参数化查询的标准方法是什么?

【问题讨论】:

  • joins 确实支持多个参数。 guides.rubyonrails.org/…
  • 你能不能用类似时尚的代码来展示你正在尝试做的事情,而不是仅仅用文字来解释它?您可以使用Arel::Nodes::InnerJoinArel::Nodes::OuterJoin 构建这些类型的连接,但如果没有上下文,我宁愿不直接回答
  • @engineersmnky 我用一个例子更新了帖子
  • @Glyoko 虽然它确实支持多个参数,但它自然不支持多个连接条件,例如"posts.id = images.post_id AND posts.id = 1"
  • posts.id = 1 不应该通过连接来完成。为此,您应该使用where(id: 1)joins。例如Post.some_other_scope.joins(:images).where(id: 1)

标签: ruby-on-rails activerecord


【解决方案1】:

arel“关系代数”是 Rails 的底层查询汇编器,可用于构造 Rails 不支持的高级查询、条件、连接、CTE 等。由于这个库是 Rails 不可或缺的一部分,大多数 Rails 查询方法将支持直接注入 Arel 对象而不会出现问题(老实说,大多数方法无论如何都会将您的参数转换为这些对象之一)。

在您的情况下,您可以按如下方式构建所需的连接:

  posts_table = Post.arel_table
  images_table = Image.arel_table 
  some_id = 1

  post_join = Arel::Nodes::OuterJoin.new(
    posts_table,
    Arel::Nodes::On.new(
      posts_table[:id].eq(images_table[:post_id])
        .and(posts_table[:id].eq(some_id))
    )
  )

生成的 SQL:

  post_join.to_sql
  #=> "LEFT OUTER JOIN [posts] ON [posts].[id] = [images].[post_id] AND [posts].[id] = 1"

然后您只需将此联接添加到当前查询中

  Image.joins(post_join)
  #=> SELECT images.* FROM images LEFT OUTER JOIN [posts] ON [posts].[id] = [images].[post_id] AND [posts].[id] = 1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-07
    • 2014-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多