ruby-on-rails – 使用范围在ActiveRecord中的多个DateTime范围
我有一个Session模型,它有一个:created_at日期和一个:start_time日期,它们都存储在数据库中:time.我目前正在一个巨大的表上吐出一堆结果,并允许用户使用范围过滤单个日期和可选时间范围的结果,如下所示:
class Session < ActiveRecord::Base ... scope :filter_by_date,lambda { |date| date = date.split(",")[0] where(:created_at => DateTime.strptime(date,'%m/%d/%Y')..DateTime.strptime(date,'%m/%d/%Y').end_of_day ) } scope :filter_by_time,lambda { |date,time| to = time[:to] from = time[:from] where(:start_time => DateTime.strptime("#{date} #{from[:digits]} #{from[:meridian]}",'%m/%d/%Y %r').. DateTime.strptime("#{date} #{to[:digits]} #{to[:meridian]}",'%m/%d/%Y %r') ) } end 控制器看起来或多或少像这样: class SessionController < ApplicationController def index if params.include?(:date) || params.include?(:time) && ( params[:time][:from][:digits].present? && params[:time][:to][:digits].present? ) i = Session.scoped i = i.filter_by_date(params[:date]) unless params[:date].blank? i = i.filter_by_time(params[:date],params[:time]) unless params[:time].blank? || params[:time][:from][:digits].blank? || params[:time][:to][:digits].blank? @items = i @items.sort_by! ¶ms[:sort].to_sym if params[:sort].present? else @items = Session.find(:all,:order => :created_at) end end end 我需要允许用户使用多个日期过滤结果.我收到了params作为字符串格式的逗号分隔列表,例如“07/12 / 2012,07 / 13 / 2012,07 / 17/2012”,并且需要能够在数据库中查询几个不同的日期范围,以及这些日期范围内的时间范围,并合并这些结果,因此对于例如,7月12日,7月13日和7月17日下午6:30至7:30之间的所有会议. 我一直在寻找各种不同的东西,但我无法弄清楚如何实际做到这一点.这是否可以使用范围?如果不是最好的方法是什么? 我最接近的猜测看起来像这样,但它没有返回任何东西,所以我知道这是错的. scope :filter_by_date,lambda { |date| date = date.split(",") date.each do |i| where(:created_at => DateTime.strptime(i,'%m/%d/%Y')..DateTime.strptime(i,'%m/%d/%Y').end_of_day ) end } scope :filter_by_time,time| date = date.split(",") to = time[:to] from = time[:from] date.each do |i| where(:start_time => DateTime.strptime("#{i} #{from[:digits]} #{from[:meridian]}",'%m/%d/%Y %r').. DateTime.strptime("#{i} #{to[:digits]} #{to[:meridian]}",'%m/%d/%Y %r') ) end } 另一个复杂因素是开始时间都存储为DateTime对象,因此它们已经包含固定日期,所以如果我想要返回在任何日期下午6:30到晚上7:30之间开始的所有会话,我需要找出其他的东西太.第三方负责数据,因此我无法更改其结构或存储方式,我只需要弄清楚如何进行所有这些复杂的查询.请帮忙! 编辑: 以下是我通过结合Kenichi和Chuck Vose的建议得出的解决方案: scope :filter_by_date,lambda { |dates| clauses = [] args = [] dates.split(',').each do |date| m,d,y = date.split '/' b = "#{y}-#{m}-#{d} 00:00:00" e = "#{y}-#{m}-#{d} 23:59:59" clauses << '(created_at >= ? AND created_at <= ?)' args.push b,e end where clauses.join(' OR '),*args } scope :filter_by_time,lambda { |times| args = [] [times[:from],times[:to]].each do |time| h,m,s = time[:digits].split(':') h = (h.to_i + 12).to_s if time[:meridian] == 'pm' h = '0' + h if h.length == 1 s = '00' if s.nil? args.push "#{h}:#{m}:#{s}" end where("CAST(start_time AS TIME) >= ? AND CAST(start_time AS TIME) <= ?",*args) } 此解决方案允许我从多个非连续日期返回会话或在一段时间内返回任何会话而不依赖于日期,或者将两个范围组合以按这些日期内的非连续日期和时间进行过滤.好极了! 我忽略的一个重点是where语句必须是最后一个 – 保持在每个循环内部不会返回任何内容.感谢你们两位的帮助!我现在感觉更聪明. 解决方法
就像是:
scope :filter_by_date,y = date.split '/' b = "#{y}-#{m}-#{d} 00:00:00" e = "#{y}-#{m}-#{d} 23:59:59" clauses << '(start_time >= ? AND start_time <= ?)' args.push b,*args } 和 scope :filter_by_time,lambda { |dates,time| clauses = [] args = [] dates.split(',y = date.split '/' f = time[:from] # convert to '%H:%M:%S' t = time[:to] # again,same b = "#{y}-#{m}-#{d} #{f}" e = "#{y}-#{m}-#{d} #{t}" clauses << '(start_time >= ? AND start_time <= ?)' args.push b,*args } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |