Rails: как я могу использовать .to_sql в запросе .select()

У меня есть запрос ActiveRecord:

Post.all.select { |p| Date.today < p.created_at.weeks_since(2) }

И я хочу иметь возможность видеть, какой SQL-запрос это производит, используя .to_sql

Я получаю сообщение об ошибке: NoMethodError: undefined method 'to_sql'

ТИА!

select в этом выражении содержится рубиновый блок, поэтому его невозможно представить в SQL (поскольку эта часть не работает в базе данных)
Sergio Tulentsev 10.11.2022 15:13
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
86
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вам нужно вызвать to_sql на отношения. select выполняет запрос и дает вам результат, а в результате у вас нет to_sql метода.

Есть похожие вопросы, на которые вы можете посмотреть, так как они предлагают некоторые альтернативы.

«выбрать выполняет запрос» - не обязательно. Это смотря какая select это, из Enumerable или активной записи. Post.select(:created_at) не выполняет запрос, например (и вы можете вызвать .to_sql на этом)

Sergio Tulentsev 10.11.2022 15:17
Ответ принят как подходящий

ПРОБЛЕМА

Есть 2 типа select, когда дело доходит до ActiveRecord объектов, из Документов

  1. select с блоком.

Во-первых: берет блок, чтобы его можно было использовать так же, как Array#select.
Это создаст массив объектов из базы данных для области видимости, преобразуя их в массив и перебирая их с помощью Array#select.

Это то, что вы используете прямо сейчас. Эта реализация будет загружать каждое сообщение, создавая экземпляр объекта Post, а затем перебирать каждый Post, используя Array#select, чтобы отфильтровать результаты в Array. Это крайне неэффективно, не может быть связано с другой семантикой AR (например, where, order и т. д.) и приведет к очень длительным задержкам в масштабе. (Это также является причиной вашей ошибки, потому что у Array нет метода to_sql)

  1. select со списком столбцов (или строкой, если хотите)

Во-вторых: изменяет оператор SELECT для запроса, чтобы извлекались только определенные поля...

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

Предлагаемое решение:

Вместо этого вы ищете предложение WHERE для фильтрации записей на уровне базы данных, прежде чем возвращать их в ORM.

Ваш текущий фильтр (X < Y + 2)

 Date.today < p.created_at.weeks_since(2)

что означает, что сегодняшняя дата меньше, чем Дата создания плюс 2 недели.

Мы можем инвертировать этот критерий, чтобы упростить запрос, переключив его на «Сегодняшняя дата минус 2 недели» меньше, чем «Создано в». (Х - 2 < Y)

Date.today.weeks_ago(2) < p.created_at

Это эквивалентно p.created_at > Date.today.weeks_ago(2), который мы можем преобразовать в предложение where, используя стандартные методы запроса ActiveRecord:

Post.where(created_at: Date.today.weeks_ago(2)...)

Это приведет к SQL, например:

SELECT 
  posts.*
FROM 
  posts.* 
WHERE 
  posts.created_at > '2022-10-28'

Заметки:

  • created_at — это метка времени, поэтому лучше использовать Time.now вместо Date.today.
  • Дополнительные проблемы могут быть связаны с точки зрения часового пояса, поскольку вы будете выполнять сравнения конкретных дат и времени.

Другие вопросы по теме