这一直在欺骗我一段时间…
如何在Rails ActiveRecord查询中字符串插入datetime?
# Works,but supeh ugleh: Model.where("created_at >= ?",Time.now - 5.days) # How do I do this? Model.where("created_at >= #{Time.now - 5.days}") # As is,it produces the following error message: # ActiveRecord::StatementInvalid: PG::Error: ERROR: Syntax error at or near ...
我关心的是代码可读性的原因:
# I like this better: Model.where("created_at >= #{Time.now - 5.days} OR" + \ "updated_at >= #{Time.now - 3.days}") # than this: Model.where("created_at >= ? OR updated_at >= ?",Time.now - 5.days,Time.now - 3.days)
解决方法
我建议不要使用字符串插值,有很多锋利的边缘,你可能会有更多的乐趣摆动苹果在一桶鱼钩.你应该这样做:
Model.where( 'created_at >= :five_days_ago or updated_at >= :three_days_ago',:five_days_ago => Time.now - 5.days,:three_days_ago => Time.now - 3.days )
使用(well)命名的占位符为您提供了您认为字符串插值提供的可读性和位置独立性,但很好地回避了引用,时区和格式问题,您可以对字符串进行插值.
但是如何安全地使用字符串插值?有一些事情你必须自己处理:
>引用和转义.
>时间戳格式
>也许是时区.
ActiveRecord将为您处理所有这些废话.
不要尝试引用自己的话,用司机的引用方法.您可以访问connection.quote以正确引用字符串.
任何数据库都将知道如何处理ISO 8601 timestamps,并有一个方便的iso8601方法. ISO 8601也方便地包括时区,数据库应该能够解析(但是如果不能,那么你必须用.utc手工将你的时间转换成UTC).
所以,要安全:
Model.where("created_at >= #{connection.quote((Time.now - 5.days).utc.iso8601)} " + \ "OR updated_at >= #{connection.quote((Time.now - 3.days).utc.iso8601)}")
现在不是很漂亮吗?使用ISO 8601时间戳,您应该安全地用简单的单引号代替connection.quote调用:
Model.where("created_at >= '#{(Time.now - 5.days).utc.iso8601}' " + \ "OR updated_at >= '#{(Time.now - 3.days).utc.iso8601}'")
但你仍然会有很多的噪音和丑陋,你会发展不好的习惯.