范围和字段作为Rails中的参数

时间:2011-06-07 21:52:34

标签: ruby-on-rails ruby

我在Rails模型中添加了一个范围,允许使用范围基于指定的参数字段进行搜索。这是它的样子:

scope :upcoming, lambda { |field| 
  where("to_char(#{field}, 'DDD') BETWEEN :alpha AND :omega", 
    alpha: Time.now.advance(days: 4).strftime('%j'),
    omega: Time.now.advance(days: 8).strftime('%j'),
  )
}

Event.upcoming(:registration) # Query all events with registration shortly.
Event.upcoming(:completion)   # Query all events with completion shortly.

以上工作正常,但在创建时我阅读了Ruby on Rails指南并找到了以下内容:

  

将变量直接放入条件字符串将按原样将变量传递给数据库。这意味着它将直接来自可能具有恶意意图的用户的未转义变量。如果这样做,则会使整个数据库处于危险之中,因为一旦用户发现他或她可以利用您的数据库,他们就可以做任何事情。永远不要将你的参数直接放在条件字符串中。

虽然目前从未使用用户参数调用范围,但我很好奇是否存在设置字段而不使用插值的方法,以便更好地符合上述建议。我已尝试使用另一个命名参数,但是这将使用引号转义字段(从而导致它失败)。有任何想法吗?

2 个答案:

答案 0 :(得分:2)

我建议根据模型的属性验证field参数,主要是将模型用作允许传递的值的白名单。像这样:

scope :upcoming, lambda { |field|    
  if column_names.include? field.to_s
    where("to_char(#{field}, 'DDD') BETWEEN :alpha AND :omega", 
      alpha: Time.now.advance(days: 4).strftime('%j'),
      omega: Time.now.advance(days: 8).strftime('%j'),
    )
  else
    # throw some error or return nil
  end
}

答案 1 :(得分:0)

好的,一直到最后阅读可能会有所帮助(谢谢rubyprince)。看起来您正在对在Oracle中存储日期的字段进行查询。问题是to_char正在寻找变量,而不是字符串。在rails中转义变量的行为将其转换为字符串。因此,在这种特殊情况下,您可以将:alpha和:omega转换为字段中存储的值的格式。这样你就可以直截了当地逃离现场。当然,Oracle将日期视为时间存在问题。我猜这就是为什么你为了比较而转换成年份的原因。如果您使用的是Oracle Enhanced Adapter,则可以设置

self.emulate_dates_by_column_name = true

确保该字段被视为日期。然后使用to_date函数(带一个字符串):alpha和:omega

scope :upcoming, lambda { |field| 
  where(":field BETWEEN to_date(:alpha,'yyyy/mm/dd') AND to_date(:omega,'yyyy/mm/dd')",
    field: field,
    alpha: Time.now.advance(days: 4).strftime('%Y/%m/%d'),
    omega: Time.now.advance(days: 8).strftime('%Y/%m/%d'),
  )
}

我无法对此进行测试,所以我可能会在这里杂草丛生。

根据Jordan验证用户输入总是一个好主意。