Как я могу написать область для возврата всех фильмов, которые `not_voted_by` предоставлены пользователю? - PullRequest
0 голосов
/ 13 мая 2018

В рельсах у меня есть 3 модели: Movie, Vote и User

class Movie
  has_many :votes
end

class User
  has_many :votes
end

class Vote
  belongs_to :movie
  belongs_to :user
end

У меня есть область действия voted_by для модели Movie, которая возвращает все фильмы, за которые проголосовалипользователь.

class Movie
  scope :voted_by, ->(user) {
    includes(:votes).where(votes: { user: user })
  }
end

Теперь я хочу еще одну область действия not_voted_by, которая в точности противоположна: она должна возвращать все фильмы, за которые НЕ проголосовал данный пользователь.

Как мне этого добиться?

Что я придумаю до сих пор:

scope :not_voted_by, ->(user) {
  includes(:votes).where.not(votes: { user: user }).or(
    includes(:votes).where(votes: { user: nil })
  )
}

Это работает, когда за фильм проголосовал один или ноль пользователей.Но это не работает, если за фильм проголосовали несколько пользователей.

Например, если за фильм M проголосовали оба пользователя A и B.Movie.not_voted_by(A) по-прежнему включает M, хотя не должно.

Заранее спасибо!

1 Ответ

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

Включает в SQL означает левое соединение. Таким образом, вы добавляете все записи слева, где пользователь не user. SQL

SELECT *
FROM movies
LEFT JOIN votes ON (votes.movie_id = movies.id)
WHERE votes.user_id <> 1

Если у вас есть, например, в табл.

id | movie_id | user_id
-----------------------
1  | 1        | 1
2  | 1        | 2
3  | 2        | 2

Затем вы запрашиваете исключение только первой записи, если user.id = 1.

Итак, я думаю, что вам нужно исключить фильмы с голосованием, отменив предыдущую область действия

scope :not_voted_by, ->(user) { where.not(id: voted_by(user) }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...