Usando field type daterange com Rails e PostgreSQL

Outro dia precisei criar um model que permitisse ao freelancer marcar sua disponibilidade no Bonsai. A idéia é que ele pudesse marcar que está disponível full-time, part-time ou indisponível durante um certo período de dias.

Uma boa alternativa para a clássica combinação de campos “start_date” e “end_date” foi usar o field type daterange que o PostgreSQL possui e o Rails suporta muito bem.

Como defini-lo na migration:

create_table :availabilities do |t|
  t.daterange :period
  ...
end

Trabalhando com campos daterange

Filtrar os records com períodos que comecem a partir do início da atual semana:

scope :from_current_week_onward, -> { where("lower(period) >= :beginning_of_week", beginning_of_week: Date.current.beginning_of_week) }

Pesquisar por um período exato:

Availability.where("period && daterange(:start, :end)", start: Date.current, end: 3.days.from_now)

O campo tem todos os métodos de um Range do Ruby:

a.period # => Mon, 02 Jan 2017...Mon, 09 Jan 2017
a.period.begin # => Mon, 02 Jan 2017
a.period.end # => Mon, 09 Jan 2017

Por que eu uso Date.current? Leia esse post que escrevi no blog da HE:Labs: Evitando problemas com datas e timezones no Rails.

Gotcha

Atenção pra um detalhe importante: o Rails sempre salva o range usando a versão exclusiva dela:

availability.period = Date.current.beginning_of_week..Date.current.end_of_week # => Mon, 02 Jan 2017..Sun, 08 Jan 2017
availability.save # => true
availability.reload.period # => Mon, 02 Jan 2017...Mon, 09 Jan 2017

Isso é um saco, apanhei bastante até perceber isso então espero que esse post ajude a poupar o seu tempo 😁

Quer poder definir horários nos ranges também?

Se você precisar usar horas e minutos no seu range, também é simples, basta usar o field type tsrange ao invés do daterange. 😉

Leave a Comment