我有一个具有日期属性的 ActiveRecord 模型。是否可以利用该日期属性按年、日和月查找:
Model.find_by_year(2012)
Model.find_by_month(12)
Model.find_by_day(1)
或者是否可以简单地find_by_date(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只是添加一个类方法:
Using a class method is the preferred way to accept arguments for scopes. These methods will still be accessible on the association objects...
所以你会有如下所示的类方法:
def self.by_year(year)
where('extract(year from date_column) = ?', year)
end
# etc.
关于ruby-on-rails - ActiveRecord 在日期字段上按年、日或月查找,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9624601/