我有一个带有日期属性的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.

Ruby-on-rails相关问答推荐

Ruby线程使用互斥处理并发问题

仅当未在带有ENV[';Dyno';]的Heroku问题上运行时才初始化Sidekiq Cron

方法和括号之间没有空格时出错

刺激中的Rails 7和 bootstrap 错误-无法解析模块说明符 bootstrap

在Ruby中按特定值合并时,将两个对象数组添加到一起

如何从 Rails7.2 中的控制器获取名称空间?

ActiveRecord 回调列表

如何使用默认的 Rails 记录器记录 Ruby 异常的整个回溯?

rails 3 - link_to 销毁不工作

rails:防止闪烁消息显示两次

默认情况下,如何在 Rails 中使 cookie 安全(仅限 https)?

Ruby on Rails:在模型中验证还是在数据库中验证更好?

Rails 中是否有 HTML 安全截断方法?

参数错误:范围主体需要可调用

使用 PostgreSQL 的模式和 Rails 创建多租户应用程序

rails 获取应用程序根/基本 url

如何在 Rails 应用程序中测试 ElasticSearch (Rspec)

在 Rails 中,在特定时区创建特定时间(不是现在)的最佳方式是什么?

Ruby on Rails Bootstrap Glyphicons 不工作

是否可以输出rake db:migrate产生的 SQL 更改脚本?