Лучшее решение для «одного, другого или обоих» случаев - PullRequest
0 голосов
/ 15 мая 2018

Я проверял некоторый код, и обнаружилось что-то похожее на следующее:

def between_dates(date_1, date_2)
  if date_1 && date_2
    conditions "created_at >= date_1 AND created_at <= date_2"
  elseif date_1
    conditions "created_at >= date_1"
  elseif date_2
    conditions "created_at <= date_2"
  end
end

Это выглядело как вид кода, который можно улучшить, но я не смог найти более элегантного решения для такого тривиального и обычного условного выражения.

Я ищу лучший ответ для этой проблемы, когда мы должны вернуть значение для одного, другого или обоих.

Ответы [ 4 ]

0 голосов
/ 15 мая 2018

Rails позволяет динамически создавать запрос.Вот пример использования scopes и метода класса.Поскольку области всегда возвращают объект ActiveRecord::Relation (даже если блок возвращает nil), они являются цепочечными:

class Event < ApplicationRecord
  scope :created_before, -> (date) { where('created_at <= ?', date) if date }
  scope :created_after,  -> (date) { where('created_at >= ?', date) if date }

  def self.created_between(date_1, date_2)
    created_after(date_1).created_before(date_2)
  end
end

Пример использования:

Event.created_between(nil, Date.today)
# SELECT `events`.* FROM `events` WHERE (created_at <= '2018-05-15')

Event.created_between(Date.yesterday, nil)
# SELECT `events`.* FROM `events` WHERE (created_at >= '2018-05-14')

Event.created_between(Date.yesterday, Date.today)
# SELECT `events`.* FROM `events` WHERE (created_at >= '2018-05-14') AND (created_at <= '2018-05-15')
0 голосов
/ 15 мая 2018

Я бы использовал что-то вроде этого:

def between_dates(date_1, date_2)
  parts = []

  if date_1
    parts << "created_at >= date_1"
  end

  if date_2
    parts << "created_at <= date_2"
  end

  full = parts.join(' AND ')
  conditions(full)
end

Это может быть дополнительно подтверждено многими способами, но вы поймете идею.

0 голосов
/ 15 мая 2018

Я не уверен, что это изящнее, но я всегда делаю reduce все, чтобы избежать опечаток:

[[date_1, '>='], [date_2, '<=']].
  select(&:first).
  map { |date, sign| "created_at #{sign} #{date}" }.
  join(' AND ')
0 голосов
/ 15 мая 2018
def between_dates(date_1, date_2)
  date_conditions = []
  date_conditions << 'created_at >= date_1' if date_1
  date_conditions << 'created_at <= date_2' if date_2
  conditions date_conditions.join(' AND ') unless date_conditions.empty?
end
...