参数化ActiveRecord #joins方法

时间:2019-07-03 14:24:16

标签: ruby-on-rails activerecord

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

使用:

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

因为生成的SQL如下所示:

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

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

1 个答案:

答案 0 :(得分:2)

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