2011-06-07 51 views
0

我已经将范围添加到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. 

上述工作正常,但是在创造我读on Rails的指南中的红宝石,发现如下:

直接把变量进入条件的字符串将通过数据库原来的变量。这意味着它将直接来自可能具有恶意意图的用户的非转义变量。如果你这样做,那么你就把整个数据库置于危险之中,因为一旦用户发现他或她可以利用你的数据库,他们就可以做任何事情。永远不要直接在条件字符串中输入参数。

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

回答

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 
} 
0

好吧,一直读到最后可能会有所帮助(谢谢rubyprince)。看起来您正在查询一个在Oracle中存储日期的字段。问题是,to_char正在寻找一个变量,而不是一个字符串。而在轨道中转义变量的行为将其变成一个字符串。因此,在这种情况下,您可能会将alpha和:omega转换为存储在字段中的值的格式。这样你就可以以直截了当的方式逃离现场。 Oracle将日期当作Time来处理问题当然是存在的。我猜这就是为什么你转换为比较的一年的一年。如果您使用的是Oracle增强型适配器,您可以设置为

self.emulate_dates_by_column_name = true 

确保将字段视为日期。然后使用与to_date函数(这需要一个字符串):α和:欧米茄

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验证用户输入始终是一个好主意。

+1

但我认为OP在提问中提到“这将使用引号将字段转义出来(从而导致它失败) – rubyprince 2011-06-08 11:33:42