Ruby on rails 更好地解决“一个、另一个或两个”情况

Ruby on rails 更好地解决“一个、另一个或两个”情况,ruby-on-rails,ruby,conditional,Ruby On Rails,Ruby,Conditional,我正在检查一些代码,出现了类似于以下内容的内容: 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 "cre

我正在检查一些代码,出现了类似于以下内容的内容:

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
它看起来是一种可以改进的代码,但是对于这样一个普通的条件语句,我找不到更优雅的解决方案


当我们必须为其中一个、另一个或两个返回值时,我正在寻找一个更好的解决方案。

我会使用如下方法:

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
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

这可以在很多方面进一步美化,但你明白了。

我不确定这是否更优雅,但我总是减少一切以避免打字错误:

[[date_1, '>='], [date_2, '<=']].
  select(&:first).
  map { |date, sign| "created_at #{sign} #{date}" }.
  join(' AND ')

Rails允许动态构建查询。下面是一个使用和类方法的示例。由于作用域始终返回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')

这是一个Rails问题吗?你是在尝试动态生成查询吗?你是对的,Stefan,这是一个动态查询。我会添加标签,谢谢。我能看到为什么有人会考虑这个优雅,但我个人,我不会写这样的生产代码。主要是因为代码中嵌入了太多的条件结构。例如,假设您需要为其中一个条件调用函数。蒙斯戴特什么的。现在,您的优雅减缩器崩溃了@塞尔吉奥图兰采夫:是的,这是真的。此外,添加更多的条件,例如,一打:将大大增加此代码的数量,而您的代码将因方法中的52个LOC而被rubocop拒绝。@mudasobwa touché。@maxpleaner我越是考虑这个问题,我就越认为创建的广告也应该移动到输入数组中。除非date_conditions.empty?是多余的。我只想去掉除非,但它看起来不错。在问题的最后一部分不是elsif,当没有提供日期1和日期2时,它是elsif,方法将返回与问题中相同的nil。所以我不会这么说除非是redundant@mudasobwa:取决于条件的实现方式。这不是一个内置的AR方法,是吗?为了准确地复制原始代码,除非需要这样做,或者如果我错了,这是正确的,但是这个解决方案基本上是Nermin提出的多行版本。我个人更喜欢这种方式,但你的更具可读性,我更愿意把这个版本放在prod中。@Harry:没错,我们的代码也是这样做的。只有Nermin的代码还处理不存在任何日期的情况,除非[].join'和'返回,这是可以接受的。正如我所说,我喜欢较短的代码,但这看起来更易于维护。@Harry:我同意你的看法:这是一个很好的解决方案。它不完全符合我的情况,但会作为参考保存。