OR operator in WHERE clause with Arel in Rails 4.2

The following code constructed a valid where clause with an OR operator in Rails 4.1

MyModel.where(
  MyModel.where(attribute1: 1, attribute2: 2).where_values.reduce(:or)
)

Which is roughly equivalent to the SQL

select * from my_models where (attribute1 = 1 OR attribute2 = 2)

In Rails 4.2, the same code generates an SQL query with missing values for it's bind parameters

select * from my_models where attribute1 =  OR attribute2 =  

... and generates an error due to the missing values for the bound values.

What is the equivalent code in Rails 4.2 to generate a valid query with an OR operator?

Edit:

The solution requires an Arel::Nodes::Node derived object to be used so that it can itself be combined with other conditions via AND and OR groupings.

rel = MyModel.where(attribute1: 1, attribute2: 2)
conditions = [rel.where_values.reduce(:or).to_sql, *rel.bind_values.map(&:last)]

MyModel.where(conditions)

The conditions var must be a derivative of Arel::Nodes::Node. The above solution works for simple queries, but for more complicated queries, conditions must be an Arel Node to be passed to a final query method.

I'm using the below until rails 5 is out (in rails 5 AR supports .or):

ActiveRecord::QueryMethods::WhereChain.class_eval do
  def or(*scopes)
    scopes_where_values = []
    scopes_bind_values  = []
    scopes.each do |scope|
      case scope
      when ActiveRecord::Relation
        scopes_where_values += scope.where_values
        scopes_bind_values += scope.bind_values
      when Hash
        temp_scope = @scope.model.where(scope)
        scopes_where_values += temp_scope.where_values
        scopes_bind_values  += temp_scope.bind_values
      end
    end
    scopes_where_values = scopes_where_values.inject(:or)
    @scope.where_values += [scopes_where_values]
    @scope.bind_values  += scopes_bind_values
    @scope
  end
end

With the above you can do:

MyModel.where.or(attribute1: 1, attribute2: 2)
# or
MyModel.where.or(MyModel.where(some conditions), MyModel.where(some other conditions))

How to accomplish OR operator with Rails 4 (and lower) query , You know how to query models when several conditions need to be true at It is using the Arel library, which ActiveRecord uses itself to create  Arel gem: "SELECT *" missing from where clause in rails; Arel Query CAST operation; Grouping ands and ors in AREL; OR operator in WHERE clause with Arel in Rails 4.2; How to join on subqueries using ARel? How to rewrite this RGeo query using AR/Arel? Arel - Inserting paretheses in the right place; uninitialized constant Arel::SqlLiteral in

More correctly solution based on @bsd answer, but allow arbitrary scopes on input

 ActiveRecord::QueryMethods::WhereChain.class_eval do
   def or(*scopes)
     scopes_where_values = []
     scopes_bind_values  = []
     scopes.each do |scope|
       case scope
       when ActiveRecord::Relation
         scopes_where_values << scope.where_values.reduce(:and)
         scopes_bind_values += scope.bind_values
       when Hash
         temp_scope = @scope.model.where(scope)
         scopes_where_values << temp_scope.where_values.reduce(:and)
         scopes_bind_values  += temp_scope.bind_values
       end
     end
     scopes_where_values = scopes_where_values.inject(:or)
     @scope.where_values += [scopes_where_values]
     @scope.bind_values  += scopes_bind_values
     @scope
   end
 end

P.S. Previous code by @bsd can't correctly work in little difficult case: User.where.or(User.where(rating: 3), User.where(startups: { progress: 100, rating: nil })

Result of old code is wrong:

SELECT "users".* FROM "users" WHERE (("startups"."rating" = 3 OR "startups"."progress" = 100) OR "startups"."rating" IS NULL)

Changed code generate correct:

SELECT "users".* FROM "users" WHERE ("startups"."rating" = 3 OR "startups"."progress" = 100 AND "startups"."rating" IS NULL)

OR queries with arrays as arguments in Rails 4 (Example), A protip by ravicious about rails, activerecord, sql, and arel. the where_values result and inject(:or) will add or statement between the default  Here is a whirlwind tour through the most common relational operators. These will probably cover 80% of all interaction with the database. First is the 'restriction' operator, where: users.where(users[:name].eq('amy')) # => SELECT * FROM users WHERE users.name = 'amy' What would, in SQL, be part of the SELECT clause is called in Arel a projection:

Using raw arel might be a better option:

t = MyModel.arel_table
MyModel.where(
  t[:attribute1].eq(1).or(
    t[:attribute2].eq(2)
  )
)

Using Arel to Compose SQL Queries, When faced with a query that requires an OR statement, or when needing to do numeric comparisons such as <= , many Rails developers will  Rails 4.2 changed some internals of ActiveRecord query-building, so your code for or-conditions doesn't work. More specifically, or_query method in manager.rb fails to build a valid query. The problem is that setting where_values does not affect bind_values , and the

Creating Advanced Active Record DB Queries with Arel, For now, let's focus on passing in custom-built Arel queries. :lteq_any, :lteq_all, :eql_any] # Rails 4.2 (Arel 6.0) adds the following [:between, since it is a false statement will not return any additional data from the query. Arel is smart-- taking care of SQL subtleties like precedence and correct ordering of SQL clauses for you. For example, when generating a SQL query containing an ORDER BY and a WHERE clause, Arel ensures the WHERE clause comes first. Simply put, Arel allows Rails developers to focus on the domain in their language.

where (ActiveRecord::QueryMethods), #where will also accept a hash condition, in which the keys are fields and the values are values to be searched for. Fields can be symbols or strings. Values can  Dismiss Join GitHub today. GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.

Composable SQL Queries in Rails Using Arel, Arel wraps each component of the SQL query language with Ruby project is how you tell Arel what to return in the SELECT statement. Mastering ActiveRecord and ARel Dan Shultz. @danshultz • das0118@gmail.com. Hello, my name is Dan Shultz and I have been using rails for a little over three years now although most of my time now is spent working in python and django.

Comments
  • where_values was removed from Rails 4.2 ... at least when I search the APIs I can find it in 3.x but not in 4.2. That may well be the source of your issue.
  • where_values is part of the private API in Rails 4.2... it still exists. The bind values are in bind_values... also private. The recent changes to Arel via AdequateRecord are the cause for the issue.
  • Ok, good deal. Was not 100% certain since it was 'removed' from the public API (hence the comment v. answer).
  • What does Model.where(conditions).where_values.reduce(:or).to_sql return?
  • "(attribute1 = ? OR attribute2 = ?)"
  • Where do i define the where chain method?
  • where do I put this?
  • For anyone reading this and still at rails 4+. This goes as an initializer, it's a monkey patch