我经常在Rails遇到的一个问题是:
假设我有invoices
表格,其中包含date
和days
列。
如何检索到期的所有发票?
class Invoice < ActiveRecord::Base
def self.due
where("due_date > ?", Date.today) # this doesn't work because there is no database column "due_date"
end
private
def due_date
date + days
end
end
任何人都可以告诉我如何在不必将数据库列due_date
添加到我的发票表的情况下执行此操作吗?
感谢您的帮助。
答案 0 :(得分:2)
在PostgreSQL中,adding an integer to a date
添加了许多天:
date '2001-09-28' + integer '7' = date '2001-10-05'
所以你可以简单地说:
where('due_date + days > :today', :today => Date.today)
但是,SQLite根本没有date
类型,它将日期存储为ISO 8601字符串。这意味着在日期中添加一个数字将最终连接字符串,这有点无用。 SQLite确实有一个date
function:
日期(时间字符串,修饰符,修饰符,...)
[...]
所有五个日期和时间函数都将时间字符串作为参数。时间字符串后跟零个或多个修饰符。
所以你可以说像date('2014-01-22', '+ 11 days')
之类的东西来做日期算术。这让你有了这个:
where("date(due_date, '+' || days || ' days') > :today", :today => Date.today)
值得庆幸的是,ISO 8601日期字符串可以正确地比较为字符串,因此>
仍可正常工作。
现在你遇到了同一个简单查询的两个版本。您可以检查self.connection
区分dev / SQLite和production / PostgreSQL的方式,或者查看Rails.env.production?
。这当然会在您的测试套件中留下一个漏洞。
我认为如果你打算在PostgreSQL之上进行部署,你应该停止在SQLite之上开发,你现在应该这样做,以尽量减少痛苦和痛苦。事实是,任何非平凡的应用程序都将与您在生产中使用的数据库结合在一起,或者您将不得不花费大量精力(包括针对您使用的所有不同数据库运行测试套件)来维护数据库的可移植性。数据库独立性在理论上是一个好主意,但完全不切实际,除非有人准备承担这种独立性所需的非平凡成本(时间和财富)。除非您的应用程序是另一个“15分钟博客”玩具,否则ORM不会保护您免受数据库之间的差异。
答案 1 :(得分:1)
您可以执行以下操作:
class Invoice < ActiveRecord::Base
def self.due
Invoice.all.select { |invoice| invoice.due_date > Date.today }
end
private
def due_date
date + days
end
end