我正在创建一个系统,需要确保计划中的“旅行”不会超过一圈。为此,我尝试验证start_date和end_date,以确保它们不在另一次旅行的开始和结束日期之内。
class TripdateValidator < ActiveModel::EachValidator
def validate_each(object, attribute, value)
# Check value exists as end_date is optional
if value != nil
parsed_date = Date.parse(value)
# is the start date within the range of anything in the db
trips = Trip.where(['start_date >= ? AND end_date <= ? AND user_id = ?', parsed_date, parsed_date, object.user_id])
# overlapping other trips, aghhh
object.errors[attribute] << 'oh crap' if trips
end
end
end
日期来自type =“date”字段,该字段由jQuery UI Datepicker提供支持,包含格式2011-01-01。这就是2011-01-30 00:00:00 UTC的轨道,我还不完全理解。
如果我尝试对此值使用Date.parse(),则会出现错误:
TripsController中的TypeError #create
$ _ value需要为String(nil given)
Rails.root:
/Users/phil/Sites/travlrapp.com
应用程序跟踪|框架追踪|
完整跟踪应用程序/模型/ trip.rb:29:在
validate_each'
创建'
app/controllers/trips_controller.rb:75:in
应用程序/控制器/ trips_controller.rb:74:在
`create'
每当我运行查询时,都不会返回任何内容。这可能是一个日期格式问题,我的逻辑是破碎还是我做了一些非常愚蠢的事情?被困在这一段时间谷歌没有帮助。
编辑人们关注的是Date.parse错误,但这不是主要问题。我陷入困境的是,当一切都是完全不同的格式时,我不明白如何进行日期比较。
我已经为Chronic.parse()交换了Date.parse(),现在我正在生成以下SQL查询:
SELECT "trips".* FROM "trips" WHERE (start_date >= '2011-01-26 00:00:00.000000' AND end_date <= '2011-01-26 00:00:00.000000' AND user_id = 19)
这不会返回任何内容。我测试的日期是:
开始时间:2011-02-17 00:00:00.000000 结束时间:2011-02-21 00:00:00.000000
看到我认为日期格式正确,现在看起来更像是一个逻辑问题。我怎么能验证重叠日期&gt;。
答案 0 :(得分:10)
Squeel power FTW !!!我相信你一定会喜欢它
$ gem install squeel
model.rb
Model.where{date_colum > 10.years.ago & date_column < DateTime.now}
答案 1 :(得分:3)
我主要是回复你的编辑,我认为你没有得到任何结果有两个原因:
首先:我怀疑你的解析器给你DateTime对象,而你真的只想要简单的Date对象。将DateTime传递给Rails的SQL查询生成器,它会为您提供一个'YYYY-MM-DD hh.mm.ss.uuu...'
字符串,而数据库只需要一个简单的'YYYY-MM-DD'
字符串来进行日期列比较;数据库日期解析器失败,返回NULL,所有与NULL失败的比较等等,你得到一个空的结果集。
将parsed_date
更改为parsed_date.to_date
,您应该在这方面做得好。
第二:看一下你的SQL,特别是这个块start_date >= ? AND end_date <= ?
。在我看来,如果你要检查的行程的开始日期晚于结束日期,它只会检测到碰撞。
所以请尝试我个人喜欢的start_date <= ? AND end_date >= ?
或? BETWEEN start_date AND end_date
,因为它更具可读性。
希望这有帮助!
答案 2 :(得分:3)
对于重叠验证,您可以尝试使用其中一个宝石https://github.com/chrisb87/range_validator或https://github.com/robinbortlik/validates_overlap
答案 3 :(得分:3)
对于那些登陆的人,请查看范围条件Rails guides:
Client.where(created_at: (Time.now.midnight - 1.day)..Time.now.midnight)
这将产生以下SQL:
SELECT * FROM clients WHERE (clients.created_at BETWEEN '2008-12-21 00:00:00' AND '2008-12-22 00:00:00')
因此,您可以使用范围搜索两个日期之间的字段。
答案 4 :(得分:2)
我更喜欢:
Model.where{date_colum >> (10.years.ago..Datetime.now)}
答案 5 :(得分:0)
您是否尝试过使用TimeZone
课程:
parsed_date = Time.zone.parse(value)
这是文档:
http://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html#method-i-parse
答案 6 :(得分:0)
我会记录“值”并查看它是否远程接近Date.parse()可以处理的内容。如果它看起来可以解析,看看Date.parse是否在irb中工作,如果是,请在控制台env(./script/console或rails c)中查看它的应用程序。那应该追查问题。
答案 7 :(得分:0)
这个怎么样?
overlaps = Trip.where(
"(DATEDIFF(start_date, ?) * DATEDIFF(?, end_date)) >= 0",
self.end_date,
self.start_date
)
它基本上是这样说的:
如果每个开始日期都看向另一个结束日期,那么他们是否正在寻找 在同一个方向?然后他们重叠。
答案 8 :(得分:0)
您可以使用cover method
如果所选范围之间的数据为假,则返回true