Reputation: 1675
How can I select all database entries with a given date and month in a datetime? I tried this:
scope :with_year_and_month, ->(year, month) {
where("YEAR(created_at) = ? AND MONTH(created_at) = ?", month, year)
}
Now that would work perfectly fine in a MySQL database, but in an Sqlite database it fails because Sqlite hasn't implemented the MONTH()
and YEAR()
functions. The following works fine though in Sqlite:
scope :with_year_and_month, ->(year, month) {
where("strftime('%m', created_at) = ? AND strftime('%Y', created_at) = ?", "%02d" % month, year.to_s)
}
How would I do this in a database agnostic way?
Upvotes: 5
Views: 4213
Reputation: 42799
I think you should let active record handle this, since it checks what database it's using and uses a driver for each database, the trick is to find a generic query to run, for me this is what I could come up with, might not be the best but I'm open for suggestions
scope :with_year_and_month, ->(year, month) {
where(created_at: Date.new(year,month,1)..Date.new(year,month,-1))
}
This will generate a between query
WHERE created_at BETWEEN '2015-02-01' AND '2015-02-28'
I think this should work with you
If created_at is DateTime
then you should replace the Date
with DateTime
object so you don't miss the time between 2015-02-28 00:00:00
and 2015-02-28 23:59:59
, but you'll need extra parameters for the time
scope :with_year_and_month, ->(year, month) {
where(created_at: DateTime.new(year,month,1)..DateTime.new(year,month,-1, -1, -1, -1))
}
of course you could create a small helper function to return those dates and shorten your method.
The result would be
Where created_at BETWEEN '2015-02-01 00:00:00' AND '2015-02-28 23:59:59'
Update:
So after a couple of comments, here's the final version
scope :with_year_and_month, ->(year, month) {
date = DateTime.new(year,month)
where(created_at: date...date.next_month)
}
The generated query would look like this
created_at >= '2015-02-01 00:00:00' AND created_at < '2015-03-01 00:00:00'
Upvotes: 6