189
votes

How do you do an OR query in Rails 3 ActiveRecord. All the examples I find just have AND queries.

Edit: OR method is available since Rails 5. See ActiveRecord::QueryMethods

14
Learn SQL. ActiveRecord makes it easy to get things working, but you still need to know what your queries are doing, otherwise your project may not scale. I also thought I could get by without ever having to deal with SQL, and I was very wrong about that. - ryan0
@ryan0, you are so right. We may use fancy gems and other things, but we should be aware of what these gems are doing inside and what the underlying technology is, and maybe use the underlying technologies without the help of the gem, if need may arise, for the sake of performance. Gems are created with a specific number of usecases in mind, but there may be situations where one of the usecase in our project might be different. - rubyprince
Since Rails 5, IMHO the accepted answer should be Greg Olsen version: Post.where(column: 'something').or(Post.where(other: 'else')) - Philipp Claßen
This question has a tag of ruby-on-rails-3. Why would the accepted answer relate only to Rails 5? - iNulty

14 Answers

113
votes

Use ARel

t = Post.arel_table

results = Post.where(
  t[:author].eq("Someone").
  or(t[:title].matches("%something%"))
)

The resulting SQL:

ree-1.8.7-2010.02 > puts Post.where(t[:author].eq("Someone").or(t[:title].matches("%something%"))).to_sql
SELECT     "posts".* FROM       "posts"  WHERE     (("posts"."author" = 'Someone' OR "posts"."title" LIKE '%something%'))
218
votes

If you want to use an OR operator on one column's value, you can pass an array to .where and ActiveRecord will use IN(value,other_value):

Model.where(:column => ["value", "other_value"]

outputs:

SELECT `table_name`.* FROM `table_name` WHERE `table_name`.`column` IN ('value', 'other_value')

This should achieve the equivalent of an OR on a single column

160
votes

in Rails 3, it should be

Model.where("column = ? or other_column = ?", value, other_value)

This also includes raw sql but I dont think there is a way in ActiveRecord to do OR operation. Your question is not a noob question.

64
votes

An updated version of Rails/ActiveRecord may support this syntax natively. It would look similar to:

Foo.where(foo: 'bar').or.where(bar: 'bar')

As noted in this pull request https://github.com/rails/rails/pull/9052

For now, simply sticking with the following works great:

Foo.where('foo= ? OR bar= ?', 'bar', 'bar')

Update: According to https://github.com/rails/rails/pull/16052 the or feature will be available in Rails 5

Update: Feature has been merged to Rails 5 branch

38
votes

Rails has recently added this into ActiveRecord. It looks to be released in Rails 5. Committed to master already:

https://github.com/rails/rails/commit/9e42cf019f2417473e7dcbfcb885709fa2709f89

Post.where(column: 'something').or(Post.where(other: 'else'))

# => SELECT * FROM posts WHERE (column = 'something') OR (other = 'else)
23
votes

Rails 5 comes with an or method. (link to documentation)

This method accepts an ActiveRecord::Relation object. eg:

User.where(first_name: 'James').or(User.where(last_name: 'Scott'))
15
votes

If you want to use arrays as arguments, the following code works in Rails 4:

query = Order.where(uuid: uuids, id: ids)
Order.where(query.where_values.map(&:to_sql).join(" OR "))
#=> Order Load (0.7ms)  SELECT "orders".* FROM "orders" WHERE ("orders"."uuid" IN ('5459eed8350e1b472bfee48375034103', '21313213jkads', '43ujrefdk2384us') OR "orders"."id" IN (2, 3, 4))

More information: OR queries with arrays as arguments in Rails 4.

7
votes

The MetaWhere plugin is completely amazing.

Easily mix OR's and AND's, join conditions on any association, and even specify OUTER JOIN's!

Post.where({sharing_level: Post::Sharing[:everyone]} | ({sharing_level: Post::Sharing[:friends]} & {user: {followers: current_user} }).joins(:user.outer => :followers.outer}
5
votes

Just add an OR in the conditions

Model.find(:all, :conditions => ["column = ? OR other_column = ?",value, other_value])
4
votes

You could do it like:

Person.where("name = ? OR age = ?", 'Pearl', 24)

or more elegant, install rails_or gem and do it like:

Person.where(:name => 'Pearl').or(:age => 24)
3
votes

I just extracted this plugin from client work that lets you combine scopes with .or., ex. Post.published.or.authored_by(current_user). Squeel (newer implementation of MetaSearch) is also great, but doesn't let you OR scopes, so query logic can get a bit redundant.

3
votes

With rails + arel, a more clear way:

# Table name: messages
#
# sender_id:    integer
# recipient_id: integer
# content:      text

class Message < ActiveRecord::Base
  scope :by_participant, ->(user_id) do
    left  = arel_table[:sender_id].eq(user_id)
    right = arel_table[:recipient_id].eq(user_id)

    where(Arel::Nodes::Or.new(left, right))
  end
end

Produces:

$ Message.by_participant(User.first.id).to_sql 
=> SELECT `messages`.* 
     FROM `messages` 
    WHERE `messages`.`sender_id` = 1 
       OR `messages`.`recipient_id` = 1
-4
votes
Book.where.any_of(Book.where(:author => 'Poe'), Book.where(:author => 'Hemingway')
-4
votes

I'd like to add this is a solution to search multiple attributes of an ActiveRecord. Since

.where(A: param[:A], B: param[:B])

will search for A and B.