Railsで検索条件を指定するときはプレースホルダーではなくHashにしたほうがいい

文字列の場合

下記の場所で タイムゾーン考慮処理と、 DateTime#to_s を呼び出しているので時間まで残る

def quoted_date(value)
  if value.acts_like?(:time)
    zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal

    if value.respond_to?(zone_conversion_method)
      value = value.send(zone_conversion_method)
    end
  end

  result = value.to_s(:db)
  if value.respond_to?(:usec) && value.usec > 0
    "#{result}.#{sprintf("%06d", value.usec)}"
  else
    result
  end
end

rails/quoting.rb at e53430fa9af239e21e11548499d814f540d421e5 · rails/rails · GitHub で呼ばれているメソッドより抜粋

Hashの場合

こちらは DateTime#to_date を呼び出しているので、時間は切り落とされて日付だけが返却される

def cast_value(value)
  if value.is_a?(::String)
    return if value.empty?
    fast_string_to_date(value) || fallback_string_to_date(value)
  elsif value.respond_to?(:to_date)
    value.to_date
  else
    value
  end
end

rails/date.rb at e53430fa9af239e21e11548499d814f540d421e5 · rails/rails · GitHubより抜粋

いつから入ったのか?

どうもこれっぽい。

github.com

本来はどうあるべきなのだろうか

MySQL5.7で検証しているが 2019-02-132019-02-13 00:00:00 にしても検索結果はヒットする。しかし、しかし、MySQL5.6時点の MySQL :: MySQL 5.6 リファレンスマニュアル :: 9.1.3 日付リテラルと時間リテラル を見ると 2019-02-13 == 2019-02-13 00:00:00 とはどこにも書いてない。Date型は日付だけを持っており時間を持っていないので当たり前だが。

DBという固く設計・実装すべき方に合わせるほうが良いので、プレースホルダーの方を日付型にすれば良いと思ったが、下記で話をされている通り、そちらはカラムの型を持っていないのでDatetimeなのかDateなのかわからないため変換ができない。

github.com

アプリケーションエンジニアができることはなんだろうか?

テストかけ