合并两个ActiveRecord :: Relation对象

Pat*_*ann 165 ruby-on-rails arel rails-activerecord

假设我有以下两个对象:

first_name_relation = User.where(:first_name => 'Tobias') # ActiveRecord::Relation
last_name_relation  = User.where(:last_name  => 'Fünke') # ActiveRecord::Relation
Run Code Online (Sandbox Code Playgroud)

是否有可能将两个关系结合起来产生一个ActiveRecord::Relation包含两个条件的对象?

注意:我知道我可以链接这些行为来获得这种行为,我真正感兴趣的是我有两个独立的ActiveRecord::Relation对象.

And*_*all 186

如果要使用AND(交集)组合,请使用merge:

first_name_relation.merge(last_name_relation)
Run Code Online (Sandbox Code Playgroud)

如果要使用OR(union)组合,请使用or(在ActiveRecord 5+中可用,或在4.2中通过where或backport):

first_name_relation.or(last_name_relation)
Run Code Online (Sandbox Code Playgroud)

  • 是否有合并的"OR"版本? (76认同)
  • 没有为我工作返回空的activerecord :: relation (11认同)
  • 我真的希望Rails现在提供一种OR/UNION关系的方法...... (9认同)
  • @minohimself可能因为这是合并你们两个关系的实际结果.请注意,`merge`是一个交集,而不是union. (8认同)
  • 为了将来参考,2015年1月在ActiveRecord :: Relation中添加了`#或'方法,它将成为**Rails 5.0**的一部分,将于2015年底发布.它允许使用OR运算符组合在哪里或有HAVING条款.如果您在正式发布之前需要,可以结帐HEAD.参见[Merge Pull Request#16052](https://github.com/rails/rails/commit/9e42cf019f2417473e7dcbfcb885709fa2709f89)@Arcolye @AndrewMarshall @ Aldo-xoen-Giambelluca (5认同)
  • [这个](/sf/answers/1180811481/) 和 `#or` 正是我正在寻找的。我扩展了 ActiveRecord::Relation 来支持 Rails 4 项目中的“#or”,而不是 gem。假设相同的模型:`klass.from("(#{to_sql} union #{other_relation.to_sql}) as #{table_name}")` (2认同)

tha*_*way 36

关系对象可以转换为数组.这无法在之后使用任何ActiveRecord方法,但我不需要.我这样做了:

name_relation = first_name_relation + last_name_relation
Run Code Online (Sandbox Code Playgroud)

Ruby 1.9,rails 3.2

  • 它不作为数组,它将您的关系转换为数组.然后你不能再使用像.where()那样的ActiveRecord方法...... (66认同)
  • 最初的问题是:"是否有可能将两个关系结合起来产生一个包含两个条件的ActiveRecord :: Relation对象?" 这个答案返回一个数组...... (7认同)
  • 这是惊人的,其中一个很少发现很棒的快速胜利! (5认同)
  • 如果您不关心返回类型是关系,则可以使用first_name_relation | 组合多个结果。姓氏关系。“|” 运算符也适用于多种关系。结果值是一个数组。 (2认同)

小智 21

merge实际上并不像OR.这只是交集(AND)

我努力解决这个问题,将ActiveRecord :: Relation对象合并为一个,我没有找到任何有效的解决方案.

我没有从这两个集合中搜索正确的方法来创建联合,而是专注于集合的代数.你可以用De Morgan定律以不同的方式做到这一点

ActiveRecord提供合并方法(AND),您也可以使用not method或none_of(NOT).

search.where.none_of(search.where.not(id: ids_to_exclude).merge(search.where.not("title ILIKE ?", "%#{query}%")))
Run Code Online (Sandbox Code Playgroud)

你在这里(A u B)'= A'^ B'

更新:上述解决方案适用于更复杂的情况.在你的情况下smth就足够了:

User.where('first_name LIKE ? OR last_name LIKE ?', 'Tobias', 'Fünke')
Run Code Online (Sandbox Code Playgroud)


6ft*_*Dan 15

通过使用Rails的内置Arel,即使在很多奇怪的情况下,我也能够做到这一点.

User.where(
  User.arel_table[:first_name].eq('Tobias').or(
    User.arel_table[:last_name].eq('Fünke')
  )
)
Run Code Online (Sandbox Code Playgroud)

这通过使用Arel 或者合并两个ActiveRecord关系.


正如这里所建议的那样,合并对我不起作用.它从结果中删除了第二组关系对象.

  • 这是最好的答案,IMO.它对OR类型查询完美无缺. (2认同)

ech*_*cho 14

有一个名为active_record_union的gem 可能就是你要找的东西.

它的示例用法如下:

current_user.posts.union(Post.published)
current_user.posts.union(Post.published).where(id: [6, 7])
current_user.posts.union("published_at < ?", Time.now)
user_1.posts.union(user_2.posts).union(Post.published)
user_1.posts.union_all(user_2.posts)
Run Code Online (Sandbox Code Playgroud)


dav*_*mcd 8

如果你使用pluck获取每个记录的标识符,将数组连接在一起然后最终对这些连接的id进行查询,这就是我"处理"它的方式:

  transaction_ids = @club.type_a_trans.pluck(:id) + @club.type_b_transactions.pluck(:id) + @club.type_c_transactions.pluck(:id)
  @transactions = Transaction.where(id: transaction_ids).limit(100)
Run Code Online (Sandbox Code Playgroud)


ste*_*iel 6

如果你有一个activerecord关系数组并希望将它们全部合并,你可以这样做

array.inject(:merge)
Run Code Online (Sandbox Code Playgroud)