Programming

Combine two ActiveRecordRelation objects

25 September 2026 · 10 min read

Combine two ActiveRecordRelation objects

In the world of Ruby on Rails, ActiveRecord provides a powerful interface for interacting with databases. One common challenge developers face is efficiently manipulating and combining data retrieved through ActiveRecord queries. Specifically, the need to combine two ActiveRecord::Relation objects arises frequently when building complex applications that require merging results from different queries or scopes. Mastering techniques to effectively combine these relations ensures optimized database performance and cleaner, more maintainable code. This article will explore several strategies, providing you with the knowledge to efficiently and effectively merge your ActiveRecord queries, thereby enhancing your application’s overall performance and scalability. We will cover simple concatenation to more advanced techniques, offering practical examples for different scenarios.

Understanding ActiveRecord::Relation Objects

Before diving into the methods for combining ActiveRecord::Relation objects, it’s crucial to understand what they are. An ActiveRecord::Relation is essentially a representation of a database query, not the actual data itself. This “lazy loading” behavior is a key feature of ActiveRecord, allowing you to chain methods together to build complex queries without immediately executing them against the database. The query is only executed when you try to access the data, such as by iterating over the relation or calling a method like .to_a or .first. This characteristic is essential for optimizing database interactions, as it allows ActiveRecord to defer execution until absolutely necessary, potentially reducing the number of database round trips.

Consider a scenario where you need to fetch all active users and all admin users. Instead of fetching each group separately and then merging them in Ruby, you can build two ActiveRecord::Relation objects and then combine them using the techniques we will discuss. This approach pushes the work to the database, which is generally more efficient. Furthermore, understanding the immutability of ActiveRecord::Relation objects is vital; most methods return a new relation object rather than modifying the original in place. This immutability promotes predictable behavior and helps prevent unexpected side effects in your code. Knowing these core principles will help you effectively combine two ActiveRecord::Relation objects.

According to the Ruby on Rails documentation, ActiveRecord::Relation objects are designed to be composable, meaning they can be easily combined and modified to create more complex queries. This composability is a cornerstone of ActiveRecord’s design, enabling developers to build sophisticated data access logic with relative ease. This feature is not only useful for combining queries but also for creating reusable scopes and query modifiers that can be applied across your application.

Techniques to Combine ActiveRecord::Relation Objects

Several approaches exist for combining ActiveRecord::Relation objects, each with its own trade-offs in terms of performance and readability. The most straightforward method is to use the + operator or the concat method. However, these methods load all the records from both relations into memory before merging them, which can be inefficient for large datasets. A more efficient approach involves using SQL’s UNION or UNION ALL operations, which are performed directly by the database. These operations avoid loading all records into memory, making them much faster for large datasets. Rails provides ways to leverage these SQL features within ActiveRecord.

Another method, particularly useful when dealing with simple queries, is to use merge. The merge method combines the conditions and scopes of two relations. However, it’s crucial to understand how merge handles conflicting conditions; typically, the conditions from the relation being merged into take precedence. Therefore, carefully consider the order in which you merge relations to ensure the desired outcome. When selecting the appropriate method to combine two ActiveRecord::Relation objects, consider the size of your datasets, the complexity of your queries, and the specific requirements of your application.

For the best performance with large datasets, the general recommendation is to use SQL-based solutions like UNION or UNION ALL. These methods push the merging operation down to the database level, which is generally much more efficient than performing the merge in Ruby code.

Using UNION and UNION ALL for Efficient Combination

Leveraging SQL’s UNION and UNION ALL offers a performant way to combine two ActiveRecord::Relation objects. UNION removes duplicate records from the combined result set, while UNION ALL includes all records, even duplicates. Choosing between them depends on whether you need to eliminate duplicates, with UNION ALL generally being faster since it skips the duplicate removal process. To use these in Rails, you’ll often need to construct the SQL query manually and then execute it using find_by_sql.

Here’s an example of using UNION ALL:

relation1 = User.where(status: 'active') relation2 = User.where(role: 'admin') sql = "({relation1.to_sql}) UNION ALL ({relation2.to_sql})" combined_users = User.find_by_sql(sql) 

This code snippet constructs a SQL query that combines the results of two ActiveRecord relations using UNION ALL. The to_sql method converts each relation into its corresponding SQL query, and then the combined query is executed using find_by_sql. The result is an array of User objects representing the combined result set. Always be aware of potential SQL injection vulnerabilities when constructing SQL queries manually. Sanitize inputs and use parameterized queries whenever possible. This approach allows the database to optimize the query execution, resulting in faster performance, especially when working with large datasets.

The key advantage of using UNION or UNION ALL is that the database handles the merging and duplicate removal (in the case of UNION), which is typically much faster than performing these operations in Ruby. Furthermore, this approach avoids loading all the records into memory at once, which can be crucial when dealing with very large tables. For instance, if you’re combining two relations that each contain millions of records, using UNION or UNION ALL can significantly reduce memory usage and improve performance.

Leveraging merge for Simpler Queries

The merge method provides a simpler way to combine two ActiveRecord::Relation objects, particularly when dealing with relations that have compatible scopes and conditions. This method combines the conditions and scopes of two relations into a single relation. It’s especially useful when you want to apply additional filters or constraints to an existing relation. However, it’s essential to understand how merge handles conflicting conditions; typically, the conditions from the relation being merged into take precedence.

Consider this example:

active_users = User.where(status: 'active') premium_users = User.where(membership_type: 'premium') combined_users = active_users.merge(premium_users) 

In this scenario, combined_users will represent a relation that includes users who are both active and have a premium membership. The merge method effectively combines the where clauses from both relations. It’s important to note that if both relations had a where clause on the same attribute (e.g., status), the where clause from active_users (the relation being merged into) would take precedence. The merge method is best suited for situations where you want to add additional constraints to an existing relation without complex SQL manipulations. This method is useful for creating reusable scopes and query modifiers that can be applied across your application.

The primary advantage of using merge is its simplicity and readability. It allows you to combine relations in a concise and expressive manner, making your code easier to understand and maintain. However, it’s crucial to be aware of how merge handles conflicting conditions to ensure that the resulting relation behaves as expected. This method is not suitable for complex scenarios where you need to combine relations with different structures or when you need to perform more advanced SQL operations like UNION or UNION ALL. merge is a valuable tool for simple query combinations, but it’s essential to choose the right tool for the job based on the complexity of your query and the size of your dataset.

Best Practices and Performance Considerations

When you combine two ActiveRecord::Relation objects, optimizing for performance and maintainability is critical. Avoid loading large datasets into memory unnecessarily by using database-level operations like UNION or UNION ALL. Always profile your queries to identify performance bottlenecks and optimize accordingly. Use indexes on frequently queried columns to speed up query execution. It’s also important to write clear and concise code that is easy to understand and maintain. Use meaningful variable names and comments to explain complex logic.

Consider the following best practices:

  • Use UNION or UNION ALL for large datasets.
  • Profile your queries to identify performance bottlenecks.
  • Use indexes on frequently queried columns.
  • Write clear and concise code.

Furthermore, be mindful of N+1 queries, a common performance issue in Rails applications. N+1 queries occur when your application executes one query to fetch a list of records, and then executes N additional queries to fetch related data for each record. This can significantly degrade performance, especially when dealing with large datasets. Use eager loading (includes, preload, or eager_load) to avoid N+1 queries. Eager loading allows you to fetch related data in a single query, reducing the number of database round trips. By following these best practices, you can ensure that your ActiveRecord queries are performant and maintainable, leading to a better user experience and a more robust application.

Real-World Examples and Use Cases

Consider a social networking application where you need to display a combined feed of posts from users a particular user follows and posts from groups they are a member of. You can combine two ActiveRecord::Relation objects containing these posts to create a unified feed. Another example is an e-commerce platform where you want to display search results that combine products from different categories that match the search query. Combining the results from each category-specific query into a single result set is a common use case.

Here are some other use cases:

  • Combining search results from different models.
  • Creating a unified feed of content from different sources.
  • Merging data from different tables based on certain criteria.

Let’s say you have a blogging platform. Imagine needing to display a list of articles that are either trending or recently published. You could create two ActiveRecord relations: one for trending articles (e.g., those with a high number of views in the past week) and another for recently published articles (e.g., those published in the last 24 hours). By combining these two relations using UNION ALL, you can create a single list of articles that meet either of these criteria. This provides a dynamic and engaging experience for your users, ensuring they see both popular and fresh content. You can find more information on Active Record Querying in the official Rails documentation. These scenarios demonstrate the versatility and power of combining ActiveRecord::Relation objects in real-world applications. Efficiently managing and combining these relations can significantly improve the performance and user experience of your application. Remember to choose the right technique based on the specific requirements of your application and the size of your datasets.

To further improve query performance in these scenarios, consider using database indexes on the columns used in your where clauses and order clauses. Database indexes can significantly speed up query execution, especially when dealing with large tables. For example, if you’re frequently querying articles based on their published_at date, creating an index on the published_at column can improve the performance of your queries. According to a study by PostgreSQL documentation, proper indexing can improve query performance by orders of magnitude. Always analyze your query patterns and create indexes accordingly to optimize your database performance.

FAQ: Combining ActiveRecord::Relation Objects

**Q: What is an ActiveRecord::Relation object?**
A: An ActiveRecord::Relation object represents a database query. It's a lazy-loaded object that allows you to chain methods together to build complex queries without immediately executing them against the database.
**Q: What are the different ways to combine ActiveRecord::Relation objects?**
A: You can combine them using `+`, `concat`, `merge`, `UNION`, and `UNION ALL`. The best method depends on your specific needs and the size of your datasets.
**Q: When should I use `UNION` or `UNION ALL`?**
A: Use `UNION` or `UNION ALL` when dealing with large datasets. These methods perform the merging operation at the database level, which is generally much more efficient than performing it in Ruby.
**Q: How do I avoid N+1 queries when combining relations?**
A: Use eager loading (`includes`, `preload`, or `eager_load`) **Question & Answer :** Suppose I have the following two objects:
first_name_relation = User.where(:first_name => 'Tobias') # ActiveRecord::Relation last_name_relation = User.where(:last_name => 'Fünke') # ActiveRecord::Relation 

is it possible to combine the two relations to produce one ActiveRecord::Relation object containing both conditions?

Note: I’m aware that I can chain the wheres to get this behavior, what I’m really interested in is the case where I have two separate ActiveRecord::Relation objects.

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†:

first_name_relation.or(last_name_relation) 

† Only in ActiveRecord 5+; for 4.2 install the where-or backport.