ActiveRecord .joins () и используйте .where () в объединенной модели с 2 условиями «IN», соединенными «ИЛИ» - PullRequest
0 голосов
/ 31 марта 2020

Проблема

У меня есть Post и Comment, и я хочу выбрать сообщения и использовать .joins() и .where() в комментарии, который содержит OR и имеет 2 IN условий.

Я хочу что-то, что генерирует это:

SELECT * FROM posts
INNER JOIN comments ON comments.post_id = posts.id
WHERE comments.id IN (1,2,3) OR comments.user_id IN (4,5,6)

Я бы использовал метод .or(), но он не может занять га sh.

Post.joins(Comment)
  .where({ comments: { id: [1, 2, 3] } })
  .or({ comments: { user_id: [4, 5, 6] } })      # <-- raises exception

Возможное решение

Я упростил это для удобства чтения. На самом деле это нужно для работы с адаптерами базы данных, поэтому я бы использовал Comment.connection.quote_table_name и Comment.connection.quote_column_name для правильного цитирования имен таблиц и столбцов.

ids = [1,2,3]
user_ids = [4,5,6]

clause = ""
clause += Comment.sanitize_sql_for_conditions(["comments.id IN (?)", ids]) if ids.any?
clause += " OR " if ids.any? and user_ids.any?
clause += Comment.sanitize_sql_for_conditions(["comments.user_id IN (?)", user_ids]) if user_ids.any?

Post.joins(Comment).where(clause)

Вопрос

Это работает, но кажется, что должен быть лучший способ ... есть?

1 Ответ

0 голосов
/ 31 марта 2020

Я предполагаю, что у вас есть отношение комментариев к вашему классу Post с has_many :comments, Rails достаточно умен, чтобы знать, что когда вы используете .where с именем отношения, вы думаете об идентификаторе каждого комментария, тогда вы можете просто написать идентификаторы.

Чтобы использовать ИЛИ, вы должны использовать тот же класс, который будет использоваться для построения основного запроса, например, «подзапрос» внутри или, как следует.

Пожалуйста, попробуйте следующий код:

Post.joins(:comments)
  .where(comments: [1, 2, 3])
  .or(Post.where('comments.user_id IN ?', [4, 5, 6]))

РЕЙЛИ ИЛИ: https://zaiste.net/rails_5_or_operator_active_record/
СОЕДИНЕНИЯ: https://apidock.com/rails/ActiveRecord/QueryMethods/joins

РЕДАКТИРОВАТЬ :

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

Post.joins(:comments)
  .where('comments.id in ? OR comments.user_id in ?', [1, 2, 3], [4, 5, 6])

Each ? внутри необработанного sql будет заменено параметром, переданным в .where с слева направо в том же порядке .

...