Ruby on rails 组合两个ActiveRecord::关系对象

Ruby on rails 组合两个ActiveRecord::关系对象,ruby-on-rails,rails-activerecord,arel,Ruby On Rails,Rails Activerecord,Arel,假设我有以下两个对象: first_name_relation = User.where(:first_name => 'Tobias') # ActiveRecord::Relation last_name_relation = User.where(:last_name => 'Fünke') # ActiveRecord::Relation 是否可以组合这两个关系以生成一个包含这两个条件的ActiveRecord::Relation对象 注意:我知道我可以链接获得此行为的

假设我有以下两个对象:

first_name_relation = User.where(:first_name => 'Tobias') # ActiveRecord::Relation
last_name_relation  = User.where(:last_name  => 'Fünke') # ActiveRecord::Relation
是否可以组合这两个关系以生成一个包含这两个条件的
ActiveRecord::Relation
对象


注意:我知道我可以链接获得此行为的位置,我真正感兴趣的是我有两个独立的
ActiveRecord::Relation
对象的情况。

如果要使用
(交叉点)组合,请使用:


如果要使用
(联合)进行组合,请使用†:



†仅适用于ActiveRecord 5+;对于4.2,安装后端口。

关系对象可以转换为数组。这否定了以后可以对它们使用任何ActiveRecord方法,但我不需要这样做。我这样做:

name_relation = first_name_relation + last_name_relation

Ruby 1.9、rails 3.2

merge
实际上并不像
那样工作。它只是一个简单的交叉点(

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

我没有寻找从这两个集合创建并集的正确方法,而是专注于集合代数。你可以用不同的方式使用

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

这里有(A u B)'=A'^B'

更新: 上述解决方案适用于更复杂的情况。 在您的情况下,这样的smth就足够了:

User.where('first_name LIKE ? OR last_name LIKE ?', 'Tobias', 'Fünke')

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

User.where(
  User.arel_table[:first_name].eq('Tobias').or(
    User.arel_table[:last_name].eq('Fünke')
  )
)
这将通过使用Arel的合并两个ActiveRecord关系

User.where(
  User.arel_table[:first_name].eq('Tobias').or(
    User.arel_table[:last_name].eq('Fünke')
  )
)

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

有一个名为 这可能就是你要找的

其示例用法如下所示:

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)
当前用户.posts.union(Post.published)
当前用户.posts.union(Post.published).where(id:[6,7])
当前用户.posts.union(“发布时间<?”,Time.now)
user_1.posts.union(user_2.posts).union(Post.published)
用户_1.posts.union_all(用户_2.posts)

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

array.inject(:merge)
蛮力it:

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

all_name_relations = User.none
first_name_relation.each do |ar|
  all_name_relations.new(ar)
end
last_name_relation.each do |ar|
  all_name_relations.new(ar)
end
这就是我“处理”它的方式,如果您使用Pull为每个记录获取一个标识符,将数组连接在一起,然后最终对这些连接的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)

如果我希望结果是
ActiveRecord::Relation
类型呢?@NewAlexandria是的,在所有情况下,Rails都在欺骗您对象的类。是否存在“或”版本的合并?@mino可能是因为这是合并两个关系的实际结果。请注意,
merge
是一个交集,而不是并集。为了便于将来参考,
#或
方法已于2015年1月添加到ActiveRecord::Relation,它将成为Rails 5.0的一部分,Rails 5.0将于2015年底发布。它允许使用OR运算符组合WHERE或HAVING子句。如果需要,您可以在正式发布之前签出HEAD。请参阅@Arcolye@AndrewMarshall@Aldo xoen Giambelluca更新:遗憾的是,这不会按日期合并。它不充当数组,它会将您的关系转换为数组。然后你就不能再像.where()那样使用ActiveRecord方法了……如果你不关心返回类型是关系,你可以将多个结果与first_name_relation | last_name_relation结合起来。“|”操作符也处理多个关系。结果值是一个数组。最初的问题是:“是否可以组合这两个关系来生成一个包含这两个条件的ActiveRecord::Relation对象?”这个答案返回一个数组……这对于许多情况来说是一个很好的解决方案。如果您只需要循环遍历记录的枚举(例如,您不关心它是数组还是ActiveRecord::Relation),并且不介意两个查询的开销,那么这就用简单明了的语法解决了问题。但愿我能+2它!这是最好的答案,IMO。它完美地适用于或类型查询。感谢您指出这一点,帮助了我很多。其他答案只适用于一小部分字段,但对于in语句中超过一万个ID,性能可能非常差。@KeesBriggs-这不是真的。我在Rails 4的所有版本中都使用过它(未定义的方法“stringify_keys”用于#感谢分享。即使在您的帖子发布四年后,这仍然是我从
ransack
创建联合的唯一解决方案,并且
上充当标记,同时保持我的
ActiveRecord
实例的完整性。使用此gem时,您可能无法获得由如果在模型上定义了作用域,则调用e union()。请参阅自述文件中ActiveRecord中的联合状态。可能会有帮助:
array.inject(:merge)
在rails 5.1.4中对ActiveRecord关系数组无效。但是
array.flatte!
有效。
first_name_relation = User.where(:first_name => 'Tobias') # ActiveRecord::Relation
last_name_relation  = User.where(:last_name  => 'Fünke') # ActiveRecord::Relation

all_name_relations = User.none
first_name_relation.each do |ar|
  all_name_relations.new(ar)
end
last_name_relation.each do |ar|
  all_name_relations.new(ar)
end
  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)