【问题标题】:Parametrized join in Rails 4Rails 4中的参数化连接
【发布时间】:2016-02-25 22:17:36
【问题描述】:

我正在手动操作join,我需要将参数传递给它的ON 子句:

Foo.joins("LEFT OUTER JOIN bars ON foos.id = bars.foo_id AND bars.baz = #{baz}")

有没有办法将baz 作为参数传递,以避免潜在的注入问题?有一个方法sanitize_sql_array,但我不确定在这种情况下如何使用它。

注意:我不能使用where,因为它不一样。

【问题讨论】:

  • 那么 baz 是另一个加入的模型吗?你能给我你对 baz 的价值吗?
  • 是的,很高兴知道 baz 可能是什么。
  • 例如,baz 是一个包含字符串文字或数字的变量。这不是另一个模型,它是我想在外连接中传递给 ON 条件的值。

标签: ruby-on-rails ruby-on-rails-4 parameters left-join


【解决方案1】:

使用 sanitize_sql_array,那就是:

# Warning: sanitize_sql_array is a protected method, be aware of that to properly use it in your code
ar = ["LEFT OUTER JOIN bars ON foos.id = bars.foo_id AND bars.baz = %s", baz]
# Within foo model:
sanitized_sql = sanitize_sql_array(ar)
Foo.joins(sanitized_sql)

试过了,效果很好。

【讨论】:

    【解决方案2】:

    活动记录模型有sanitize 类方法,所以你可以这样做:

    Foo.joins("LEFT OUTER JOIN bars ON foos.id = bars.foo_id AND bars.baz = #{Foo.sanitize(baz)}")
    

    __

    从 Rails 5.1 开始,它已被删除,请改用 ActiveRecord::Base.connection.quote()

    【讨论】:

    • 对于最近的查看者,此方法不再起作用,因为 sanitize 不是公共 API 的一部分,并且已在 Rails 5.1 中删除(请参阅 github.com/rails/rails/issues/28947 的讨论和解决方法)。跨度>
    【解决方案3】:

    Arel 可以做到。

    baz = "i am a baz"
    foos = Arel::Table.new('foos') # or Foo.arel_table, if this is an AR model
    bars = Arel::Table.new('bars')
    join = foos.outer_join(bars).on(
      foos[:id].eq(bars[:foo_id]),
      bars[:baz].eq(baz))
    puts join.to_sql
    

    这会产生

    SELECT FROM "foos"
    LEFT OUTER JOIN "bars" ON
      "foos"."id" = "bars"."foo_id"
      AND "bars"."baz" = 'i am a baz'
    

    现在,如果您想将其返回到 ActiveRecord 查询中,而不仅仅是打印 SQL:

    Foo.joins(join.join_sources)
    

    【讨论】:

    • 这应该是答案。使用Foo.arel_table 在代码中没有表名。
    【解决方案4】:

    我认为你应该这样尝试:

    Foo.joins("LEFT OUTER JOIN bars ON foo.id = bars.foo_id AND bars.baz = ?", baz)
    

    更多参数:

    Foo.joins("LEFT OUTER JOIN bars ON foo.id = ? AND bars.baz = ? AND ...", foo, baz, etc...)
    

    【讨论】:

    • 不幸的是,这不起作用。 baz 不被解释为参数值,而是作为另一个连接模型。你可以自己试试。 github.com/rails/rails/blob/…
    • AFAIK Rails(即使是 4.0)不支持 JOIN 子句中的参数。正如 Mladen 总结的那样,必须自己生成 SQL 语句。我想@Kulgar has it right 知道如何安全地做到这一点。
    • 您确定 baz 是作为字符串文字或整数而不是另一个 AR 对象传递的吗?
    【解决方案5】:

    如果您传递值的哈希值应该是安全的,AR 将保护您免受 SQL 注入,如下所示:

    Foo.joins("LEFT OUTER JOIN bars ON foo.id = bars.foo_id").where(bars: {baz: baz})
    

    只是不要在 sql 中使用易受 sql 注入攻击的行字符串。

    【讨论】:

    • 不幸的是,这不是我想要的。 WHERE 中的条件不等价于 ON 中的条件。
    • 由于外连接,JOIN 子句中的条件与WHERE 子句中的条件不同。见sqlfiddle.com/#!9/c827b7/5
    猜你喜欢
    • 1970-01-01
    • 2014-08-13
    • 2021-11-23
    • 1970-01-01
    • 2014-05-26
    • 1970-01-01
    • 2015-12-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多