Rectangle 27 135

If you want to combine using AND (intersection), use merge:

first_name_relation.merge(last_name_relation)

If you want to combine using OR (union), use or (available in ActiveRecord 5+, or in 4.2 via where-or backport):

first_name_relation.or(last_name_relation)

Is there an "OR" version of merge?

@minohimself Probably because that is the actual result of merging your two relations. Note that merge is an intersection, not union.

For future reference, #or method has been added to ActiveRecord::Relation on Jan 2015, and it will be part of Rails 5.0, which will ship in late 2015. It allows use of the OR operator to combine WHERE or HAVING clauses. You can checkout HEAD if you need it prior the official release. See Merge Pull Request #16052 @Arcolye @AndrewMarshall @Aldo-xoen-Giambelluca

ruby on rails - Combine two ActiveRecord::Relation objects - Stack Ove...

ruby-on-rails rails-activerecord arel
Rectangle 27 135

If you want to combine using AND (intersection), use merge:

first_name_relation.merge(last_name_relation)

If you want to combine using OR (union), use or (available in ActiveRecord 5+, or in 4.2 via where-or backport):

first_name_relation.or(last_name_relation)

Is there an "OR" version of merge?

@minohimself Probably because that is the actual result of merging your two relations. Note that merge is an intersection, not union.

For future reference, #or method has been added to ActiveRecord::Relation on Jan 2015, and it will be part of Rails 5.0, which will ship in late 2015. It allows use of the OR operator to combine WHERE or HAVING clauses. You can checkout HEAD if you need it prior the official release. See Merge Pull Request #16052 @Arcolye @AndrewMarshall @Aldo-xoen-Giambelluca

ruby on rails - Combine two ActiveRecord::Relation objects - Stack Ove...

ruby-on-rails rails-activerecord arel
Rectangle 27 30

Relation objects can be converted to arrays. This negates being able to use any ActiveRecord methods on them afterwards, but I didn't need to. I did this:

name_relation = first_name_relation + last_name_relation

It doesn't act as an array, it converts your relation to an array. Then you can't use ActiveRecord methods on it like .where() anymore ...

If you don't care about return type being relation, you can combine multiple results with first_name_relation | last_name_relation. The "|" operator works on multiple relations as well. The result value is an array.

ruby on rails - Combine two ActiveRecord::Relation objects - Stack Ove...

ruby-on-rails rails-activerecord arel
Rectangle 27 30

Relation objects can be converted to arrays. This negates being able to use any ActiveRecord methods on them afterwards, but I didn't need to. I did this:

name_relation = first_name_relation + last_name_relation

It doesn't act as an array, it converts your relation to an array. Then you can't use ActiveRecord methods on it like .where() anymore ...

If you don't care about return type being relation, you can combine multiple results with first_name_relation | last_name_relation. The "|" operator works on multiple relations as well. The result value is an array.

ruby on rails - Combine two ActiveRecord::Relation objects - Stack Ove...

ruby-on-rails rails-activerecord arel
Rectangle 27 12

relation & relation
Model.joins("join relationships ON user_id = followed_id").where("follower_id = {user.id}") & Model.where(:user_id => user.id)

This forces ActiveRecord to put the results in an array eagerly. Can this be done with lazy loading?

The & method on ActiveRecord::Relation is a alias for merge, and this alias has been removed as of Rails 3.0.9. It was removed for exactly the confusion that @MikeJohnson points out: it's not the appropriate operator. Use relation.merge(other_relation) instead.

@zzawaideh just wondering if you have any idea how you solved this problem I am trying to retrieve two tables but need it as ActiveRecord::Relation not an array. any help would be much appreciated

Wow, so "merge" puts them together with an AND. What would be the OR equivalent?

ruby on rails - Combine two ActiveRecord Query results - Stack Overflo...

ruby-on-rails activerecord ruby-on-rails-3
Rectangle 27 19

merge
OR
AND

Instead of searching for right method creating an union from these two sets, I focused on algebra of sets. You can do it in different way using De Morgan's law

ActiveRecord provides merge method (AND) and also you can use not method or none_of (NOT).

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

UPDATE: The solution above is good for more complex cases. In your case smth like that will be enough:

User.where('first_name LIKE ? OR last_name LIKE ?', 'Tobias', 'Fnke')

ruby on rails - Combine two ActiveRecord::Relation objects - Stack Ove...

ruby-on-rails rails-activerecord arel
Rectangle 27 19

merge
OR
AND

Instead of searching for right method creating an union from these two sets, I focused on algebra of sets. You can do it in different way using De Morgan's law

ActiveRecord provides merge method (AND) and also you can use not method or none_of (NOT).

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

UPDATE: The solution above is good for more complex cases. In your case smth like that will be enough:

User.where('first_name LIKE ? OR last_name LIKE ?', 'Tobias', 'Fnke')

ruby on rails - Combine two ActiveRecord::Relation objects - Stack Ove...

ruby-on-rails rails-activerecord arel
Rectangle 27 12

I've been able to accomplish this, even in many odd situations, by using Rails' built-in Arel.

User.where(
  User.arel_table[:first_name].eq('Tobias').or(
    User.arel_table[:last_name].eq('Fnke')
  )
)

Merge, as was suggested here, didn't work for me. It dropped the 2nd set of relation objects from the results.

Thanks for pointing this out, helped me out a lot. The other answers only work for a small subset of fields, but for upwards of ten thousand ids in the IN statement, the performance can be very bad.

@KeesBriggs that's not true. I've used this in all versions of Rails 4.

ruby on rails - Combine two ActiveRecord::Relation objects - Stack Ove...

ruby-on-rails rails-activerecord arel
Rectangle 27 12

I've been able to accomplish this, even in many odd situations, by using Rails' built-in Arel.

User.where(
  User.arel_table[:first_name].eq('Tobias').or(
    User.arel_table[:last_name].eq('Fnke')
  )
)

Merge, as was suggested here, didn't work for me. It dropped the 2nd set of relation objects from the results.

Thanks for pointing this out, helped me out a lot. The other answers only work for a small subset of fields, but for upwards of ten thousand ids in the IN statement, the performance can be very bad.

@KeesBriggs that's not true. I've used this in all versions of Rails 4.

ruby on rails - Combine two ActiveRecord::Relation objects - Stack Ove...

ruby-on-rails rails-activerecord arel
Rectangle 27 9

There is a gem called active_record_union that might be what you are looking for.

It's example usages is the following:

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)

Thanks for sharing. Even four years after your post this has been the only solution for me to create a union from ransack and acts-as-taggable-on while keeping my ActiveRecord instances intact.

When using this gem, you may not get an ActiveRecord::Relation returned by the union() call if you have scopes defined on the model. See State of the Union in ActiveRecord in the Readme.

ruby on rails - Combine two ActiveRecord::Relation objects - Stack Ove...

ruby-on-rails rails-activerecord arel
Rectangle 27 9

There is a gem called active_record_union that might be what you are looking for.

It's example usages is the following:

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)

Thanks for sharing. Even four years after your post this has been the only solution for me to create a union from ransack and acts-as-taggable-on while keeping my ActiveRecord instances intact.

When using this gem, you may not get an ActiveRecord::Relation returned by the union() call if you have scopes defined on the model. See State of the Union in ActiveRecord in the Readme.

ruby on rails - Combine two ActiveRecord::Relation objects - Stack Ove...

ruby-on-rails rails-activerecord arel
Rectangle 27 42

Coming in Rails 4

In Rails 4, a chainable ActiveRecord::NullRelation will be returned from calls like Post.none.

The returned ActiveRecord::NullRelation inherits from Relation and implements the Null Object pattern. It is an object with defined null behavior and always returns an empty array of records without quering the database.

ruby on rails - How to return an empty ActiveRecord relation? - Stack ...

ruby-on-rails activerecord relation
Rectangle 27 2

Can I paginate the array resulting from a|b without loading every record from the database?

Yes, you can paginate array. Only you need to do is require 'will_paginate/array' file where your are using paginate for array. If you are using in many place then its better to add it in config/initializers. And its array so it won't load every record from database each time (i.e.) query is fired only once. To load association you can use eager load on array using include.

First of all thanks for your answer!. One more question, paginate on a Relation object is loading 30 objects from the database each page. If I do c=a|b and paginate that array, it will load all the records at once from the database into an array and then show 30 of them for each page. If the number of records is very high it could be a problem.Should I do something like c=a.limit(200).offset(@page*30)|b.limit(200).offset(@page*30) to avoid that? Would something like that work and is that the easier way to do it?

One thing I am not clear why are you getting same active relations in two different object and combining them?? Why don't you write single query to get results??

One of them is returned from a function with a where query(User.feed function), the other one is returned through an association(User.mentioned_in where mentioned_in is an association defined by: has_many :mentioned_in, through: :mention_relationships, source: :post etc.), the two relation objects are not the same. To write a single query i'd have to write the query for the association too and join them. I guess in the end i'll have to do it that way, but I thought there could be another(better) way to do it without changing much code.

In both case you have only objects, right? Then a.merge(b) should return ActiveRecord::Relation. Why is in your case its empty?

My fault sorry, you are right, I don't know why I thought that b(which in my case is User.mentioned_in) was an ActiveRecord::Relation but it wasn't, User.mentioned_in seems to return an Array. When I wrote the question I was testing everything in the rails console but I must have copied the wrong variables. Thanks for all your answers!

ruby on rails - Combine two ActiveRecord::Relation with OR, not AND, r...

ruby-on-rails ruby activerecord will-paginate relation
Rectangle 27 3

This is how I've "handled" it if you use pluck to get an identifier for each of the records, join the arrays together and then finally do a query for those joined ids:

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)

ruby on rails - Combine two ActiveRecord::Relation objects - Stack Ove...

ruby-on-rails rails-activerecord arel
Rectangle 27 3

This is how I've "handled" it if you use pluck to get an identifier for each of the records, join the arrays together and then finally do a query for those joined ids:

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)

ruby on rails - Combine two ActiveRecord::Relation objects - Stack Ove...

ruby-on-rails rails-activerecord arel
Rectangle 27 355

There is a now a "correct" mechanism in Rails 4:

>> Model.none 
=> #<ActiveRecord::Relation []>

So far this hasn't been back ported to 3.2 or earlier. Only edge (4.0)

Just tried with Rails 4.0.5 and it's working. This feature made it to the Rails 4.0 release.

@AugustinRiedinger Model.scoped does what you're looking for in rails 3.

As of Rails 4.0.5, Model.none doesn't work. You need to use one of your real model names, e.g. User.none or what-have-you.

ruby on rails - How to return an empty ActiveRecord relation? - Stack ...

ruby-on-rails activerecord relation
Rectangle 27 70

A more portable solution that doesn't require an "id" column and doesn't assume there won't be a row with an id of 0:

scope :none, where("1 = 0")

I'm still looking for a more "correct" way.

Yeah I'm really surprised that these answers are the best we have. I think ActiveRecord/Arel must still be pretty immature. If I had to go through perambulations to create an empty array in Ruby I'd be really annoyed. Same thing here, basically.

Although somewhat hackish, this is the correct way for Rails 3.2. For Rails 4, see @steveh7 's other answer here: stackoverflow.com/a/10001043/307308

scope :none, -> { where("false") }

ruby on rails - How to return an empty ActiveRecord relation? - Stack ...

ruby-on-rails activerecord relation
Rectangle 27 110

You can convert an array of objects arr to an ActiveRecord::Relation like this (assuming you know which class the objects are, which you probably do)

MyModel.where(id: arr.map(&:id))

You have to use where though, it's a useful tool which you shouldn't be reluctant to use. And now you have a one-liner converting an array to a relation.

map(&:id) will turn your array of objects to an array containing only their id's. And passing an array to a where clause will generate a SQL statement with IN that looks something like:

SELECT .... WHERE `my_models`.id IN (2, 3, 4, 6, ....

Keep in mind that the ordering of the array will be lost - But since your objective is only to run a class method on the collection of these objects, I assume it won't be a problem.

Well done, exactly what I needed. You can use this for any attribute on the model. works perfectly for me.

Why build literal SQL yourself when you can do where(id: arr.map(&:id))? And strictly speaking, this doesnt convert the array to a relation, but instead gets new instances of the objects (once the relation is realized) with those IDs which may have different attribute values than the already in-memory instances in the array.

Very inefficient! You've turned a collection of objects you already have in memory into ones you are going to do a database query to access. I would look at refactoring those class methods you are wanting to iterate over the array.

ruby on rails - Converting an array of objects to ActiveRecord::Relati...

ruby-on-rails ruby activerecord