【问题标题】:Passing date parameters to a sql select query in rails (QueryMethods)将日期参数传递给rails中的sql选择查询(QueryMethods)
【发布时间】:2017-11-29 03:46:32
【问题描述】:

我正在使用brakeman gem(它可以识别Ruby on Rails 代码中可能存在的安全问题)。我们有一个使用连接、组和选择的范围,我需要更新查询的选择部分。这个范围看起来像下面这样。我将这里范围的内容放在产品模型上。

Product.joins('LEFT JOIN orders ON orders.product_id = products.id')
  .group('products.id')
  .select(
    "SUM(CASE WHEN orders.order_at BETWEEN '#{start_date}' AND '#{end_date}'" \
    " THEN orders.qty ELSE 0 END) as qty, products.*"
  )

现在如果我尝试像这样更改查询

Product.joins('LEFT JOIN orders ON orders.product_id = products.id')
  .group('products.id')
  .select(
    "SUM(CASE WHEN orders.order_at BETWEEN ? AND ?" \
    " THEN orders.qty ELSE 0 END) as qty, products.*",
    '#{start_date}',
    '#{end_date}'
  )

它给了我? 的语法错误我还尝试了一些其他的 group 和 have 方法,但它对我不起作用。我正在使用带有 rails 4.1.8 的 postgres sql
他们有什么办法可以做到这一点吗?提前致谢。

这是错误

PG::SyntaxError: ERROR: "?" 处或附近的语法错误
第 1 行:选择 SUM(CASE WHEN orders.order_at BETWEEN ? AND ? AND ord

【问题讨论】:

  • 没有足够的信息。还有here 有一个类似的无人值守问题。

标签: ruby-on-rails postgresql ruby-on-rails-4 psql


【解决方案1】:

我相信你也可以用 where 子句去掉 CASE 语句:

checkout range conditions

Product
  .joins('LEFT JOIN orders ON orders.product_id = products.id')
  .where(orders: {order_at: start_date..end_date})   # range condition
  .group('products.id')
  .select("SUM(orders.qty) as qty, products.*")

【讨论】:

    【解决方案2】:

    您使用? 语法是对的,但是您对select 的调用需要将其中一部分拆分为对where 的调用。

    此外,您正在将日期转换为字符串(例如,'#{start_date}')。这会阻止被调用的方法能够将值处理和格式化为日期。相反,只需传递原始日期(例如,start_date)。

    Product
      .joins('LEFT JOIN orders ON orders.product_id = products.id')
      .where('orders.order_at BETWEEN ? AND ?', start_date, end_date)
      .select("SUM(orders.qty) as qty, products.*")
      .group('products.id')
    

    您还可以根据 daino3 的回答 (.where(orders: {order_at: start_date..end_date})) 重做 where 呼叫。

    推理

    不要将参数直接嵌入where(或相关)调用中,这一点至关重要。这样做会使您的代码面临重大安全风险,称为SQL Injection,因为远程用户可能会放置任意数据字符串,从而触发对您的数据库执行的各种危险调用。

    这就是为什么你应该始终使用where('various sql things ?', parameter) 而不是where("various sql things #{parameter}")

    有关将参数传递给此类 Rails sql 调用的更多信息,请查看official Rails Guide on the Active Record Query Interface

    【讨论】:

    • SELECT SUM(CASE WHEN orders.order_at BETWEEN ? AND ? THEN orders.qty ELSE 0 END) as total_qty, products.*, '2017-11-28 05:00:00.000000', '2017-11-29 04:59:59.999999' FROM "products" LEFT JOIN orders ON orders.product_id = products.id GROUP BY products.id 这是生成的查询,它具有相同的错误。我认为 ?应该用日期替换,但不是,我不知道为什么。
    • 这通常是正确的做法,但不幸的是 select 方法不采用这种方式,因此您需要在将它们嵌入字符串之前自己清理它们,或者找到其他方法构建您的查询(例如@daino 的答案如何显示)。
    • 哦,是的——使用where而不是select应该可以解决这个问题。
    猜你喜欢
    • 1970-01-01
    • 2017-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-18
    • 1970-01-01
    相关资源
    最近更新 更多