This is almost a FAQ because the idea seems reasonable at first.
But that isn’t really how SQL works, nor data-handling operations in normal programming languages. When you compare a type of a lower precision to a type of a higher precision, they promote the value to the higher precision, and then compare that.
For example, if you have a floating point column called myval and one row has the value 0.5, you could obviously use where(:myval => 0.0…1.0) to find it using floating point numbers for the range. Now you could write a query API that treats integer values X as covering the entire range from X.0 to X.9999…, so that where(:myval => 0) would find the row that had value 0.5 - but that would be a pretty damn weird API. where(:myval => 0) and where(:myval => 0.0) would give different results!
What you are suggesting is exactly the same idea, but instead of integers you have dates, and instead of floats you have date-times. (These two concepts should be a direct mapping in your head - dates are whole numbers counted since some arbitrary start date (most of us use 1 Jan 0 CE, some things use 1 Jan 1970 for unixy reasons - whatever); times are arbitrary-precision subdivisions of the whole days. The precision you get is even configurable per column in many databases.)
No-one does this because it’s inconsistent and although it would give the result that you want in this situation, it produces completely counterintuitive results in other situations.
For example, if where(:created_at => Date.yesterday) includes some row R, then you would also expect that where(“created_at <= ?”, Date.yesterday) would also find row R and so would where(“created_at > ?”, Date.yesterday).
Now think about how to make that work. When we see a Date value, how do we know to treat it as 00:00:00 or 23:59:59.9999… so that both of those where ranges can work?
It’s not possible, and so to introduce a special case for the equality case that does not also work for inequalities and more general parameter substitution is going to lead to a lot of very confused programmers and buggy code.
So, like I say, SQL doesn’t do this, and neither does any language binding that I know of. There has to be one consistent rule to compare types of different precisions, and the only sensible way to do this is to promote the lower type to the higher precision rather than do the reverse.
That means that a date being compared to a time is always equivalent to 00:00:00 on the day, the same way that 42 being compared to a float is equivalent to 42.0000. Making ActiveRecord do anything other would be bizarre.
Also, to ease your pain my suggestion would be that you don’t write that out manually if you do it a lot. Duckpunch a method that returns the range:
User.where(:created_at => Date.yesterday.anytime)