假设我有以下两个对象:
first_name_relation = User.where(:first_name => 'Tobias') # ActiveRecord::Relation
last_name_relation = User.where(:last_name => 'Fünke') # ActiveRecord::Relation
是否可以将这两种关系结合起来生成一个包含这两个条件的
ActiveRecord::Relation
对象?
注意:我知道我可以链接 wheres 来获得此行为,我真正感兴趣的是我有两个单独的
ActiveRecord::Relation
对象的情况。
关系对象可以转换为数组。这使得之后无法对它们使用任何 ActiveRecord 方法,但我不需要这样做。我这样做了:
name_relation = first_name_relation + last_name_relation
Ruby 1.9,Rails 3.2
merge
实际上不像OR
那样工作。简直就是交集(AND
)
我努力解决这个问题,将 ActiveRecord::Relation 对象合并为一个,但没有找到任何可行的解决方案。
我没有寻找从这两个集合创建并集的正确方法,而是专注于集合的代数。您可以使用德摩根定律
以不同的方式做到这一点ActiveRecord 提供了 merge 方法(AND),也可以使用 not 方法或 none_of(NOT)。
search.where.none_of(search.where.not(id: ids_to_exclude).merge(search.where.not("title ILIKE ?", "%#{query}%")))
你这里有 (A u B)' = A' ^ B'
更新: 上述解决方案适用于更复杂的情况。 在你的情况下,这样就足够了:
User.where('first_name LIKE ? OR last_name LIKE ?', 'Tobias', 'Fünke')
即使在许多奇怪的情况下,我也能够通过使用 Rails 的内置 Arel 来完成此任务。
User.where(
User.arel_table[:first_name].eq('Tobias').or(
User.arel_table[:last_name].eq('Fünke')
)
)
这通过使用 Arel 的 or 合并了两个 ActiveRecord 关系。
合并,正如这里所建议的那样,对我来说不起作用。它从结果中删除了第二组关系对象。
有一个叫做 active_record_union 的宝石 这可能就是您正在寻找的。
其示例用法如下:
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)
这就是我“处理”它的方式,如果您使用 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)
如果你有一个 ActiveRecord 关系数组并想将它们全部合并,你可以这样做
array.inject(:merge) # like where AND
array.inject(:or) # like where OR
在使用 or 不可压缩的情况下,我使用类似的方法来获取 ActiveRecord_Relation 对象
User.from("(#{complex_raw_query} UNION #{complex_raw_query}) AS users")
暴力破解:
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
希望这对那里的人有用——您可以进行第二次查询以按 id 查找匹配项:
ids = last_name_relation.ids + first_name_relation.ids
User.where(id: ids)
我意识到这对于 3 个数据库请求可能不是最有效的,但它可以完成工作并且很容易理解。