我在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指南并找到了以下内容:
将变量直接放入条件字符串将按原样将变量传递给数据库。这意味着它将直接来自可能具有恶意意图的用户的未转义变量。如果这样做,则会使整个数据库处于危险之中,因为一旦用户发现他或她可以利用您的数据库,他们就可以做任何事情。永远不要将你的参数直接放在条件字符串中。
虽然目前从未使用用户参数调用范围,但我很好奇是否存在设置字段而不使用插值的方法,以便更好地符合上述建议。我已尝试使用另一个命名参数,但是这将使用引号转义字段(从而导致它失败)。有任何想法吗?
答案 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验证用户输入总是一个好主意。