Подтвердить что ты не робот

Как мне это сделать? Model.where( "created_at >= # {Time.now - 5.days}" )

Это некоторое время искажало меня...

Как я могу выполнить интерполяцию строки datetime в запросах Rails ActiveRecord?

# Works, but supeh ugleh:
Model.where("created_at >= ?", Time.now - 5.days)

# How do I do this?
Model.where("created_at >= #{Time.now - 5.days}")
# As is, it produces the following error message:
# ActiveRecord::StatementInvalid: PG::Error: ERROR:  syntax error at or near ...

Причиной, по которой я забочусь, является читаемость кода:

# I like this better:
Model.where("created_at >= #{Time.now - 5.days} OR" + \
            "updated_at >= #{Time.now - 3.days}")

# than this:
Model.where("created_at >= ? OR updated_at >= ?", Time.now - 5.days, Time.now - 3.days)
4b9b3361

Ответ 1

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

Model.where(
    'created_at >= :five_days_ago or updated_at >= :three_days_ago',
    :five_days_ago  => Time.now - 5.days,
    :three_days_ago => Time.now - 3.days
)

Использование (ну) названных заполнителей дает вам читабельность и независимость позиции, которые, по вашему мнению, предлагают интерполяция строк, но прекрасно обойти проблемы цитирования, часового пояса и формата, которые накладывают на вас интерполяцию строк.

Но как вы безопасно используете интерполяцию строк? Есть несколько вещей, которые вы должны решить сами:

  • Цитирование и экранирование.
  • Формат временной отметки.
  • Может быть, и часовые пояса.

ActiveRecord позаботится обо всем этом ерунде для вас.

Не пытайтесь делать цитаты самостоятельно, используйте методы цитирования драйверов. У вас будет доступ к connection.quote для правильного цитирования строк.

Любая база данных будет знать, что делать с временными метками ISO 8601, и для этого существует удобный метод iso8601. ISO 8601 также удобно включает часовой пояс, и база данных должна быть способна анализировать это (но если это не возможно, вам придется конвертировать свое время в UTC вручную с помощью .utc).

Итак, чтобы быть в безопасности:

Model.where("created_at >= #{connection.quote((Time.now - 5.days).utc.iso8601)} " + \
         "OR updated_at >= #{connection.quote((Time.now - 3.days).utc.iso8601)}")

Не так красиво это сейчас? С отметками времени ISO 8601 вы должны безопасно заменить вызовы connection.quote на простые одинарные кавычки:

Model.where("created_at >= '#{(Time.now - 5.days).utc.iso8601}' " + \
         "OR updated_at >= '#{(Time.now - 3.days).utc.iso8601}'")

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

Мы не участвуем в вечеринках, как программисты PHP в 1999 году, поэтому не поддавайтесь ложной лени, используя строчную интерполяцию в вашем SQL, используйте именованные заполнители.

Ответ 2

Старый вопрос, но мой предпочтительный метод:

Model.where(created_at: 5.days.ago..Time.current)

Гораздо симпатичнее и читабельнее.

Кроме того, Rails 3.2 представил некоторые вспомогательные вспомогательные методы поддержки, чтобы получить некоторые общие диапазоны, Time#all_day, Time#all_week, Time#all_quarter и Time#all_year, так что вы могли бы, например:

Model.where(created_at: Time.current.all_week)