Rails 3 запрос ActiveRecord с использованием операторов SQL IN и SQL OR - PullRequest
16 голосов
/ 17 ноября 2010

Я пишу запрос к Rails 3 ActiveRecord с использованием синтаксиса «где», который использует оба оператора SQL IN и SQL OR и не может понять, как использовать их оба вместе.

Этот код работает (в моей модели User):

Question.where(:user_id => self.friends.ids)
#note: self.friends.ids returns an array of integers

, но этот код

Question.where(:user_id => self.friends.ids OR :target => self.friends.usernames)

возвращает эту ошибку

syntax error, unexpected tCONSTANT, expecting ')'
...user_id => self.friends.ids OR :target => self.friends.usern...

Любая идея, как написать это вRails, или просто каким должен быть необработанный SQL-запрос?

Ответы [ 4 ]

46 голосов
/ 17 ноября 2010

Вам не нужно использовать необработанный SQL, просто укажите шаблон в виде строки и добавьте именованные параметры:

Question.where('user_id in (:ids) or target in (:usernames)', 
               :ids => self.friends.ids, :usernames => self.friends.usernames)

Или позиционные параметры:

Question.where('user_id in (?) or target in (?)', 
               self.friends.ids, self.friends.usernames)

Вы также можете использовать превосходный камень Squeel , как @erroric указал в своем ответе (блок my { } необходим только в том случае, если вам нужен доступ к self или переменным экземпляра):

Question.where { user_id.in(my { self.friends.ids }) |
                 target.in(my { self.friends.usernames }) }
9 голосов
/ 18 апреля 2011

Хотя Rails 3 AR не дает вам оператора или, вы все равно можете достичь того же результата, не переходя к SQL и не используя непосредственно Arel.Под этим я подразумеваю, что вы можете сделать это следующим образом:

t = Question.arel_table
Question.where(t[:user_id].in(self.friends.ids).or(t[:username].in(self.friends.usernames)))

Некоторые могут сказать, что это не так красиво, некоторые могут сказать, что это довольно просто, потому что не содержит SQL.В любом случае, он наверняка может быть красивее, и для него тоже есть жемчужина: MetaWhere

Для получения дополнительной информации см. Этот сайт: http://railscasts.com/episodes/215-advanced-queries-in-rails-3 и сайт MetaWhere: http://metautonomo.us/projects/metawhere/

ОБНОВЛЕНИЕПозже Райан Бейтс сделал еще одну рассылку о мета-локации и метаисследовании: http://railscasts.com/episodes/251-metawhere-metasearch Позже, хотя мета-локация (и поиск) стали более или менее унаследованными жемчужинами.Т.е. они даже не работают с Rails 3.1.Автор чувствовал, что они (Metawhere и search) нуждаются в решительном переписывании.Настолько, что он на самом деле пошел на новый драгоценный камень все вместе.Преемником Metawhere является Squeel.Узнайте больше об объявлении авторов здесь: http://erniemiller.org/2011/08/31/rails-3-1-and-the-future-of-metawhere-and-metasearch/ и посетите домашнюю страницу проекта: http://erniemiller.org/projects/squeel/ "Metasearch 2.0" называется Ransack, и вы можете прочитать о нем кое-что здесь: http://erniemiller.org/2011/04/01/ransack-the-library-formerly-known-as-metasearch-2-0/

6 голосов
/ 14 января 2013

Кроме того, вы можете использовать Squeel. На мой взгляд, это проще. Вы можете выполнить операции IN (>>) и OR (|), используя следующий синтаксис:

Question.where{(:user_id >> my{friends.id}) | (:target >> my{friends.usernames})}

Я обычно оборачиваю свои условия в (...), чтобы обеспечить надлежащий порядок работы - оба IN происходят перед ИЛИ.

Блок my{...} выполняет методы из контекста self, как определено перед вызовом Squeel - в данном случае Question. Внутри блока Squeel self относится к объекту Squeel, а не к объекту Question (, см. Readme Squeel для получения дополнительной информации ). Вы можете обойти это, используя оболочку my{...} для восстановления исходного контекста.

0 голосов
/ 17 ноября 2010

raw SQL

SELECT *
FROM table
WHERE user_id in (LIST OF friend.ids) OR target in (LIST OF friends.usernames)

с каждой запятой в списке отдельно.Я не очень хорошо разбираюсь в Rails ActiveRecord.Для AND вы бы просто поставили запятую между этими двумя условиями, но idk об OR

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