Saya memiliki model Session
yang memiliki tanggal :created_at
dan tanggal :start_time
, keduanya disimpan dalam database sebagai :time
. Saat ini saya mengeluarkan banyak hasil pada tabel besar dan memungkinkan pengguna memfilter hasil berdasarkan satu tanggal dan rentang waktu opsional menggunakan cakupan, seperti:
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
Pengontrolnya kurang lebih terlihat seperti ini:
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
Saya perlu mengizinkan pengguna memfilter hasil menggunakan beberapa tanggal. Saya menerima params sebagai daftar yang dipisahkan koma dalam format string, mis. "07/12/2012,07/13/2012,07/17/2012"
, dan harus dapat menanyakan database untuk beberapa rentang tanggal yang berbeda, dan rentang waktu dalam rentang tanggal tersebut, dan menggabungkan hasilnya, jadi misalnya semua sesi pada 12/7, 13/7, dan 17/7 antara 18:30 dan 19:30.
Saya telah mencari ke mana-mana dan mencoba beberapa hal berbeda tetapi saya tidak tahu bagaimana cara melakukannya. Apakah ini mungkin menggunakan cakupan? Jika tidak, apa cara terbaik untuk melakukan ini?
Tebakan terdekat saya terlihat seperti ini tetapi tidak menghasilkan apa pun jadi saya tahu itu salah.
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, lambda { |date, 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
}
Kerumitan lainnya adalah semua waktu mulai disimpan sebagai objek DateTime sehingga sudah menyertakan tanggal tetap, jadi jika saya ingin mengembalikan semua sesi yang dimulai antara pukul 18:30 dan 19:30 pada tanggal mana pun, saya perlu memikirkan hal lain. juga. Pihak ketiga bertanggung jawab atas data tersebut, jadi saya tidak dapat mengubah struktur atau penyimpanannya, saya hanya perlu memikirkan cara melakukan semua pertanyaan rumit ini. Tolong bantu!
EDIT:
Inilah solusi yang saya temukan dengan menggabungkan saran Kenichi dan Chuck Vose di bawah ini:
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)
}
Solusi ini memungkinkan saya untuk mengembalikan sesi dari beberapa tanggal yang tidak berturut-turut ATAU mengembalikan sesi apa pun dalam rentang waktu tanpa bergantung pada tanggal sama sekali, ATAU menggabungkan dua cakupan untuk memfilter berdasarkan tanggal dan waktu yang tidak berturut-turut dalam tanggal tersebut. Hore!
Poin penting yang saya abaikan adalah bahwa pernyataan where
harus berada di urutan terakhir -- menyimpannya di dalam setiap loop tidak akan menghasilkan apa-apa. Terima kasih kepada Anda berdua atas semua bantuan Anda! Saya merasa lebih pintar sekarang.