ActiveRecord Find By Year, Day или Month в поле Date

У меня есть модель ActiveRecord, у которой есть атрибут даты. Можно ли использовать этот атрибут даты для поиска по Году, Дню и Месяцу:

Model.find_by_year(2012) Model.find_by_month(12) Model.find_by_day(1) 

или это просто возможно find_by_date (2012-12-1).

Я надеялся, что смогу избежать создания атрибутов Год, Месяц и День.

10 Solutions collect form web for “ActiveRecord Find By Year, Day или Month в поле Date”

Предполагая, что ваш «атрибут даты» является датой (а не полной меткой времени), тогда простой, 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 слишком глуп, чтобы понять их, поэтому при попытке их использовать будет большой беспорядок; поэтому, если вы обнаружите, что эти запросы слишком медленные, вам придется добавить три дополнительных столбца, которые вы пытаетесь избежать.

Если вы собираетесь использовать эти запросы много, вы можете добавить области для них, но рекомендуемый способ добавить область с аргументом – это просто добавить метод classа:

Использование метода classа является предпочтительным способом принятия аргументов для областей. Эти методы все равно будут доступны для объектов ассоциации …

Таким образом, у вас будут методы classа, которые выглядят следующим образом:

 def self.by_year(year) where('extract(year from date_column) = ?', year) end # etc. 

Независимая версия базы данных …

 def self.by_year(year) dt = DateTime.new(year) boy = dt.beginning_of_year eoy = dt.end_of_year where("published_at >= ? and published_at < = ?", boy, eoy) end 

Для MySQL попробуйте это

 Model.where("MONTH(date_column) = 12") Model.where("YEAR(date_column) = 2012") Model.where("DAY(date_column) = 24") 

В вашей модели:

 scope :by_year, lambda { |year| where('extract(year from created_at) = ?', year) } 

В вашем controllerе:

 @courses = Course.by_year(params[:year]) 

Я думаю, что самый простой способ сделать это – это область:

 scope :date, lambda {|date| where('date_field > ? AND date_field < ?', DateTime.parse(date).beginning_of_day, DateTime.parse(date).end_of_day} 

Используйте его так:

 Model.date('2012-12-1').all 

Это вернет все модели с полем date_field между началом и концом дня для даты отправки.

Мне нравится ответ BSB, но как область действия

 scope :by_year, (lambda do |year| dt = DateTime.new(year.to_i, 1, 1) boy = dt.beginning_of_year eoy = dt.end_of_year where("quoted_on >= ? and quoted_on < = ?", boy, eoy) end) 

Это было бы еще одно:

 def self.by_year(year) where("published_at >= ? and published_at < = ?", "#{year}-01-01", "#{year}-12-31") end 

Хорошо работает для меня в SQLite.

Попробуй это:

 Model.where("MONTH(date_column) = ? and DAY(date_column) = ?", DateTime.now.month, DateTime.now.day) 

Простая реализация только за год

приложение / модели / your_model.rb

 scope :created_in, ->(year) { where( "YEAR( created_at ) = ?", year ) } 

Применение

 Model.created_in(1984) 

Нет необходимости в методе extract , это работает как прелесть в postgresql:

 text_value = "1997" # or text_value = '1997-05-19' or '1997-05' or '05', etc sql_string = "TO_CHAR(date_of_birth::timestamp, 'YYYY-MM-DD') ILIKE '%#{text_value.strip}%'" YourModel.where(sql_string) 
Interesting Posts

Использование iptables для перенаправления IP-адреса

Как добавить аргументы командной строки (параметры) для закрепленных приложений в Windows 7?

Инъекционная инъекция с использованием Azure WebJobs SDK?

Почему const подразумевает внутреннюю связь на C ++, когда она не в C?

Использование Maven для множественной среды развертывания (производство / разработка)

Как вы показываете рабочий стол в Windows 7?

Не удается уловить событие нажатия кнопки кнопки панели инструментов

Ограничение импорта приложений create-react-app вне каталога src

Гиперссылка на другой рабочий лист с использованием функции гиперссылки в excel

прохождение 2 $ индексных значений внутри вложенного ng-repeat

Как использовать деление с плавающей запятой в bash?

Почему используется пейджинг?

Outlook 2013 сбрасывает напоминание о встрече до 0 минут после принятия приглашения

URL-адреса с косой чертой в параметре?

Apple Wireless (алюминий) Клавиатура в Windows

Давайте будем гением компьютера.