Rails 3使用SQL IN和SQL OR运算符进行ActiveRecord查询

我正在使用“where”语法编写Rails 3 ActiveRecord查询,该语法使用SQL IN和SQL OR运算符,并且无法弄清楚如何将它们一起使用。

此代码有效(在我的用户模型中):

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查询应该是什么?

原始SQL

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

每个列表逗号分开。 我不太了解Rails ActiveRecord的东西。 对于AND,你只需在这两个条件之间加一个逗号,但是关于OR的idk

您不需要使用原始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 gem,正如@erroric在他的回答中指出的那样(仅当您需要访问self或实例变量时才需要my { }块):

 Question.where { user_id.in(my { self.friends.ids }) | target.in(my { self.friends.usernames }) } 

虽然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。 无论如何,它肯定会更漂亮,也有它的gem:MetaWhere

有关详细信息,请参阅此railscast: http: //railscasts.com/episodes/215-advanced-queries-in-rails-3和MetaWhere站点: http ://metautonomo.us/projects/metawhere/

更新:后来Ryan Bates又制作了关于metawhere和元搜索的另一个轨道广播: http: //railscasts.com/episodes/251-metawhere-metasearch后来虽然Metawhere(和搜索)已成为或多或少的遗产gem。 即他们甚至不使用Rails 3.1。 作者觉得他们(Metawhere和搜索)需要大幅改写。 实际上他真的去了一块新gem。 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-元搜索-2-0 /

或者,您可以使用Squeel。 在我看来,它更简单。 您可以使用以下语法完成IN( >> )和OR( | )操作:

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

我通常将我的条件包含在(...)以确保适当的操作顺序 – IN都发生在OR之前。

my{...}块在Squeel调用之前定义的self上下文中执行方法 – 在本例中为Question 。 在Squeel块内部, self指的是Squeel对象而不是Question对象( 有关更多信息,请参阅Squeel自述文件 )。 您可以使用my{...}包装器来恢复原始上下文。