在 Rails 中,如何编写一个带有“where”的查找器来比较两个日期?
Posted
技术标签:
【中文标题】在 Rails 中,如何编写一个带有“where”的查找器来比较两个日期?【英文标题】:In Rails, how do you write a finder with "where" that compares two dates? 【发布时间】:2021-12-26 23:30:13 【问题描述】:我使用的是 Rails 4.2。我有一个具有这些日期时间属性的模型
submitted_at
created_at
如何编写一个查找器方法来返回所有模型,其中提交的字段按时间顺序出现在 created_at 字段之前?我试过这个
MyModel.where(:submitted_at < :created_at)
但这会返回我数据库中的所有内容,甚至是不匹配的项目。
【问题讨论】:
为什么 submit_at 会在 created_at 之前发生?通常 created_at 是保存记录时自动设置的时间戳。 隐藏着巨大的奥秘MyModel.where(MyModel.arel_table[:submitted_at].lt(MyModel.arel_table[:created_at]))
。我也可以看到很多次提交可能早于创建,例如在这些情况下,手动输入、数据轮询、导入等数据在系统中创建之前绝对可以以某种其他形式存在。
@engineersmnky 我可能会早于 created_at 但是,IMO 这很令人困惑。即使您手动导入,我会说它们应该......相等。
@razvans 非常好,但如果我今天给你发一份文件,那么我今天就提交了。如果你直到下周才导入它,我提交它时它不会改变。我帮助创建了多个执行批处理的系统,其中文件的处理出于计时目的而延迟,但实际提交日期和时间为后代保留,因此“提交日期”总是早于自动填充的 created_at
【参考方案1】:
where(:submitted_at < :created_at)
实际上是where(false)
。当您将两个符号与 lt/gt 运算符进行比较时,您实际上只是在按字母顺序比较它们:
:a < :b # true
:c > :b # true
where(false)
或blank? 的任何其他参数只返回一个“无作用域”的链接关系。
ActiveRecord 查询界面实际上并没有直接的方法来比较这样的列。
您可以使用 SQL 字符串:
Resource.where('resources.submitted_at < resources.created_at')
或者使用 Arel 创建查询:
r = Resource.arel_table
Resource.where(r[:submitted_at].lt(r[:created_at]))
结果完全相同,但 Arel 解决方案可以说更具可移植性,并且避免了对表名进行硬编码(或创建模棱两可的查询)。
【讨论】:
【参考方案2】:您可以使用.to_sql
查看生成了什么查询。
对于你来说,它看起来像这样:
Resource.where(:submitted_at < :created_at).to_sql
# => SELECT `resources`.* FROM `resources`
如果你像下面这样更新,你会得到一些结果:
Resource.where('submitted_at < created_at')
# => SELECT * FROM `resources` WHERE (submitted_at < created_at)
【讨论】:
这会打印出 sql 但您如何在 Rails 控制台中实际打印出结果? 如果你打算在一个范围内使用它,那么在没有指定表名的情况下使用created_at
势必会导致一个模棱两可的查询,因为它在一般的 Rails 应用程序中的几乎每个表上。
已更新。只需删除.to_sql
,只是为了看看它是否有效。可以加.count
、.first
等
@max 如果你加入,你是对的。
嗯,编写范围时的经验法则是,您不知道以后将如何使用它。具体一点。以上是关于在 Rails 中,如何编写一个带有“where”的查找器来比较两个日期?的主要内容,如果未能解决你的问题,请参考以下文章
Rails - 如何编写一个链接,该链接将被调用以在控制器中调用带有参数的操作?