Rails Dates Time和Fixtures

时间:2010-12-03 21:42:46

标签: ruby-on-rails activerecord fixtures

我有以下装置:

link_1:
  user: tom
  image: boy1
  created_at: <%= 5.day.ago %>

我尝试了以下请求:

Links.where("Date(created_at) = ?", 5.day.ago.to_date)

答案:

[]

GRRRR ....输入...输入... ...刮伤 我终于尝试过:

link_1:
  user: tom
  image: boy1
  created_at: <%= 5.day.ago.to_date %>

Links.where("Date(created_at) = ?", 5.day.ago.to_date)

最后回答

[#<Link id: 298486374, user_id: 1038054164, image_id: 482586125, created_at: "2010-11-28 00:00:00", updated_at: "2010-12-03 21:32:19">]

我的期待是什么,但为什么我需要提交to_date?我不清楚,因为当我创建一个没有指定创建日期的对象时,我可以使用以下where子句选择它们而不会出现问题:

Links.where("Date(created_at) = ?", Date.today)

有什么想法吗?

4 个答案:

答案 0 :(得分:20)

在灯具中你应该:

created_at: <%= 5.day.ago.to_s(:db) %>

您的查询将是:

Links.where("created_at = ?", ...

让ActiveRecord处理有关从数据库移动数据到数据库的详细信息。我们使用ORM是有原因的。

Reference

答案 1 :(得分:1)

我推测这是因为创建灯具和调用查询之间的时间差。

5天前+ 0.00025毫秒&gt; 5天前

我不确定日期时间的精确度是多少,但这是我能想到的唯一可能性。当您将其转换为日期时,您删除了无关的时间信息并使两者相等。

答案 2 :(得分:1)

created_at是一个DateTime字段,5.days.ago有效地返回一个DateTime对象。此对象的设置时间与调用时相同,例如。星期六,2014年8月23日10:30: 37 ,这是放入数据库的内容。

在失败的情况下,当您稍后再次呼叫5.days.ago时(即使在同一执行中),新时间可能会有所不同,例如。 2014年8月23日星期六10:30: 38 。因此,您可以看到它们不相等,您将无法获得匹配。

当你追加.to_date时,你会得到一个Date对象,它没有时间组件。当它被持久化到数据库或在您的查询中使用时,它将始终被视为具有00:00:00(午夜)的时间。因此,日期和时间将匹配,(只要您不尝试运行灯具并在午夜完成查询)

答案 3 :(得分:0)

两种情况之间的区别在于,当您拨打to_date时,您会丢失时间值,因此最终结果是created_at时间戳设置为当天的午夜。您还可以避免TimeWithZone的时区转换。坦率地说,我们没有足够的信息来推测除此之外发生的事情。要查看确切的内容,最好的办法是查看log/test.log中的查询 - 如果您没有看到查询,可以将log_level设置为{{1}来启用查询在:debug中。您可以在此处复制并粘贴SQL查询。

@Ibz也提出了一个好点:使用config/environments/test.rb是一个好主意,因为fixture文件ERB被计算为一个字符串然后作为YAML读入,这可能会导致将值转换为字符串的一些问题。使用.to_s(:db)将解决此问题,但为了避免将来出现此问题(并获得一系列其他功能),我建议您使用factory_girl代替灯具。

在处理测试日期时,这类问题很常见 - 特别是如果您尝试通过两个日期或时间戳的相等性进行查询。要解决这些问题,我建议您过去选择任意固定日期/时间而不是.to_s(:db),或者如果您确实需要使用动态日期/时间,请使用Timecop gem来控制/冻结时间在你的测试中。