Rails 3: Как получить все сообщения, идентификаторы которых отсутствуют в данном списке?
Чтобы получить все сообщения с publisher_id
равными 10, 16 или 17, я делаю:
Post.where(:publisher_id => [10, 16, 17])
Как бы я получил все сообщения с publisher_id
не равно 10, 16 или 17 (то есть все возможные идентификаторы, кроме этих трех) ?
7 ответов:
В rails 4 мы можем сделать, как показано ниже
Post.where.not(:publisher_id => [10, 16, 17])
Он будет генерировать SQL, как показано ниже
SELECT "posts".* FROM "posts" WHERE ("posts"."publisher_id" NOT IN (10, 16, 17))
Непроверено, но должно быть похоже (используя metawhere gem):
Post.where( :id.not_eq => [10,16,17] )
Используя" чистый " синтаксис ActiveRecord, посыпанный Arel с помощью Rails 3, Вы можете сделать что-то вроде этого:
Post.where( Post.arel_table[:publisher_id].not_in([10, 16, 17]) )
Каждый отдельный ответ на этой странице неверен, потому что ни один из этих ответов не заботится обо всех случаях массива, особенно массивы, которые имеют только один элемент.
Вот пример, который будет терпеть неудачу, используя любое из "так называемых" решений на этой странице:
@ids = [1] Post.where("publisher_id NOT IN (?)", @ids) #ERROR Post.where("publisher_id NOT IN (?)", [4]) #ERROR #...etc #ALSO @ids = [] Post.where("publisher_id NOT IN (?)", @ids) #ERROR Post.where("publisher_id NOT IN (?)", []) #ERROR #...etc #The problem here is that when the array only has one item, only that element is #returned, NOT an array, like we had specified #Part of the sql that is generated looks like: #...WHERE (publisher_id NOT IN 166) #It should be: #...WHERE (publisher_id NOT IN (166))
Единственный ответ на этой странице, который действительно находится на правильном пути и заботится об этом очень важном деле, - это @Tudor Constantin. но проблема в том, что он на самом деле не показал "способ" использования своей методологии чтобы решить реальный абстрактный пример вопроса, ОП разместил (не просто используя жестко закодированные цифры).
Вот мое решение для динамического поиска идентификаторов, не входящих в Ассоциацию Activerecord, учитывая массив идентификаторов для исключения, который будет работать с массивом из n элементов (...включая n=1 и n=0)
@ids = [166] @attribute = "publisher_id" @predicate = "NOT IN" @ids = "(" + @ids.join(",") + ")" if @ids == "()" #Empty array, just set @ids, @attribute, and @predicate to nil @ids = @attribute = @predicate = nil end #Finally, make the query Post.where( [@attribute, @predicate, @ids].join(" ") ) #Part of the sql that is generated looks like: #...WHERE (publisher_id NOT IN (166)) #CORRECT! #If we had set @ids = [] (empty array) #Then the if statement sets everything to nil, and then #rails removes the blank " " space in the where clause automatically and does #the query as if all records should be returned, which #logically makes sense!
Если это помогло вам в любом случае, пожалуйста, голосуйте! Если вы запутались или не поняли один из моих комментариев, пожалуйста, дайте мне знать.