我有一个带有日期属性的ActiveRecord模型.是否可以利用该日期属性按年、日和月查找:
Model.find_by_year(2012)
Model.find_by_month(12)
Model.find_by_day(1)
或者只是有可能在2012年12月1日之前找到.
我希望可以避免创建年、月和日属性.
我有一个带有日期属性的ActiveRecord模型.是否可以利用该日期属性按年、日和月查找:
Model.find_by_year(2012)
Model.find_by_month(12)
Model.find_by_day(1)
或者只是有可能在2012年12月1日之前找到.
我希望可以避免创建年、月和日属性.
假设您的"日期属性"是一个日期(而不是完整的时间戳),那么简单的where
将为您提供"按日期查找":
Model.where(:date_column => date)
你不想要find_by_date_column
,因为那样最多只能得到一个结果.
对于年、月和日查询,您希望使用extract
SQL函数:
Model.where('extract(year from date_column) = ?', desired_year)
Model.where('extract(month from date_column) = ?', desired_month)
Model.where('extract(day from date_column) = ?', desired_day_of_month)
然而,如果您使用的是SQLite,那么您就必须处理strftime
,因为它不知道extract
是什么:
Model.where("cast(strftime('%Y', date_column) as int) = ?", desired_year)
Model.where("cast(strftime('%m', date_column) as int) = ?", desired_month)
Model.where("cast(strftime('%d', date_column) as int) = ?", desired_day_of_month)
在某些情况下,%m
和%d
格式说明符将添加前导零,这可能会混淆相等测试,因此cast(... as int)
将强制格式化字符串为数字.
ActiveRecord不会保护您免受数据库之间所有差异的影响,因此,一旦您做了任何不寻常的事情,您要么必须构建自己的可移植层(虽然很难看,但有时是必要的),要么将自己绑定到一组有限的数据库(现实的,除非您发布了必须在任何数据库上运行的内容),或者在Ruby中执行所有逻辑(对于任何不平凡的数据量来说都是疯狂的).
在大型表上,年、月和月日查询将非常缓慢.有些数据库允许您在函数结果上添加索引,但ActiveRecord太蠢了,无法理解它们,所以如果您试图使用它们,就会造成很大的混乱;因此,如果您发现这些查询太慢,那么您必须添加您试图避免的三个额外列.
如果要经常使用这些查询,那么可以为它们添加作用域,但recommended way to add a scope with an argument只是添加一个类方法:
使用类方法是接受作用域参数的首选方法.这些方法仍然可以在关联对象上访问...
所以你会有这样的类方法:
def self.by_year(year)
where('extract(year from date_column) = ?', year)
end
# etc.