Если ваш «атрибут даты» является датой (а не полной отметкой времени), тогда простой where
даст вам «найти по дате»:
Model.where(:date_column => date)
Вы не хотитеfind_by_date_column
, поскольку это даст не более одного результата.
Для запросов на год, месяц и день вы хотите использовать функцию extract
SQL:
Model.where('extract(year from date_column) = ?', desired_year)
Model.where('extract(month from date_column) = ?', desired_month)
Model.where('extract(day from date_column) = ?', desired_day_of_month)
Однако, если вы используете SQLite, вам придется возиться с strftime
, поскольку он не знает, что такое extract
:
Model.where("cast(strftime('%Y', date_column) as int) = ?", desired_year)
Model.where("cast(strftime('%m', date_column) as int) = ?", desired_month)
Model.where("cast(strftime('%d', date_column) as int) = ?", desired_day_of_month)
Спецификаторы формата %m
и %d
в некоторых случаях добавляются начальные нули, и это может привести к путанице в тестах на равенство, поэтому cast(... as int)
для принудительного преобразования форматированных строк в числа.
ActiveRecord не защитит вас от всех различий между базами данных, поэтому, как тольковы делаете что-то нетривиальное, вам нужно либо создать собственный слой переносимости (некрасиво, но иногда необходимо), привязать себя к ограниченному набору баз данных (реалистично, если вы не выпускаете что-то, что должно работать в какой-либо базе данных), или сделатьвся ваша логика в Ruby (безумно для любого нетривиального объема данных).
В больших таблицах запросы на год, месяц и день месяца будут довольно медленными.Некоторые базы данных позволяют вам добавлять индексы к результатам функций, но ActiveRecord слишком глуп, чтобы понимать их, поэтому он будет сильно мешать, если вы попытаетесь их использовать;поэтому, если вы обнаружите, что эти запросы слишком медленные, вам придется добавить три лишних столбца, которых вы пытаетесь избежать.
Если вы собираетесь использовать эти запросы часто, то выможно добавить области видимости для них, но рекомендуемый способ добавить область с аргументом - просто добавить метод класса:
Использование метода класса является предпочтительным способом получения аргументовдля областей применения.Эти методы по-прежнему будут доступны для объектов ассоциации ...
Таким образом, у вас будут методы класса, которые выглядят так:
def self.by_year(year)
where('extract(year from date_column) = ?', year)
end
# etc.