ActiveRecord Arel OR条件

Dmy*_*iak 58 ruby sql activerecord ruby-on-rails arel

如何使用逻辑OR而不是AND组合2个不同的条件?

注意:作为轨道范围生成2个条件,并且不能轻易地将其更改为where("x or y")直接类似的条件.

简单的例子:

admins = User.where(:kind => :admin)
authors = User.where(:kind => :author)
Run Code Online (Sandbox Code Playgroud)

它很容易应用和条件(对于这个特殊情况是没有意义的):

(admins.merge authors).to_sql
#=> select ... from ... where kind = 'admin' AND kind = 'author'
Run Code Online (Sandbox Code Playgroud)

但是,如何生成具有2种不同Arel关系的以下查询?

#=> select ... from ... where kind = 'admin' OR kind = 'author'
Run Code Online (Sandbox Code Playgroud)

似乎(根据Arel自述文件):

OR运算符尚不支持

但是我希望它不适用于此并期望写出如下内容:

(admins.or authors).to_sql
Run Code Online (Sandbox Code Playgroud)

Ale*_*fee 93

ActiveRecord查询是ActiveRecord::Relation对象(令人生气地不支持or),而不是Arel对象(它们).

[ 更新:从Rails 5开始,支持"或" ActiveRecord::Relation; 见/sf/answers/2327380961/ ]

但幸运的是,他们的where方法接受ARel查询对象.所以,如果User < ActiveRecord::Base......

users = User.arel_table
query = User.where(users[:kind].eq('admin').or(users[:kind].eq('author')))
Run Code Online (Sandbox Code Playgroud)

query.to_sql 现在显示令人放心:

SELECT "users".* FROM "users"  WHERE (("users"."kind" = 'admin' OR "users"."kind" = 'author'))
Run Code Online (Sandbox Code Playgroud)

为清楚起见,您可以提取一些临时的部分查询变量:

users = User.arel_table
admin = users[:kind].eq('admin')
author = users[:kind].eq('author')
query = User.where(admin.or(author))
Run Code Online (Sandbox Code Playgroud)

当然,一旦有了查询,就可以query.all用来执行实际的数据库调用.

  • 这是一个很好的答案.它需要很多赞成:). (7认同)
  • 这对我也有用.现在Rails 4已经发布了,这仍然是获得OR条件的最佳方法吗? (3认同)

jsw*_*ner 70

我参加聚会有点晚了,但这是我能提出的最佳建议:

admins = User.where(:kind => :admin)
authors = User.where(:kind => :author)

admins = admins.where_values.reduce(:and)
authors = authors.where_values.reduce(:and)

User.where(admins.or(authors)).to_sql
# => "SELECT \"users\".* FROM \"users\"  WHERE ((\"users\".\"kind\" = 'admin' OR \"users\".\"kind\" = 'author'))"
Run Code Online (Sandbox Code Playgroud)

  • 如果您的示波器有多个条件,则无法按预期工作(rails 3.2.12).问题是parens没有放在OR条件周围,导致ANDs影响整个查询而不是部分 (4认同)

Dav*_*ton 9

实际的arel页面:

OR运算符的工作方式如下:

users.where(users[:name].eq('bob').or(users[:age].lt(25)))
Run Code Online (Sandbox Code Playgroud)

  • 我看到了.它尚不支持.它是如何回答这个问题的? (2认同)

pje*_*pje 9

从我们的Rails 5开始ActiveRecord::Relation#or,允许你这样做:

User.where(kind: :author).or(User.where(kind: :admin))
Run Code Online (Sandbox Code Playgroud)

...它被翻译成你期望的sql:

>> puts User.where(kind: :author).or(User.where(kind: :admin)).to_sql
SELECT "users".* FROM "users" WHERE ("users"."kind" = 'author' OR "users"."kind" = 'admin')
Run Code Online (Sandbox Code Playgroud)