207

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

strivedi183
  • 4,749
  • 2
  • 31
  • 38
pho3nixf1re
  • 2,322
  • 2
  • 15
  • 13
  • 7
    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 Sep 30 '13 at 21:40
  • 1
    @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 Feb 26 '14 at 07:17
  • 2
    May be of help: [ActiveRecord OR query Hash notation](http://stackoverflow.com/q/31096009/3444240) – potashin Apr 09 '16 at 10:19
  • 4
    Since Rails 5, IMHO the accepted answer should be Greg Olsen version: `Post.where(column: 'something').or(Post.where(other: 'else'))` – Philipp Claßen Jan 22 '17 at 10:57
  • 6
    This question has a tag of ruby-on-rails-3. Why would the accepted answer relate only to Rails 5? – iNulty Apr 18 '17 at 11:22

14 Answers14

237

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

Soviut
  • 88,194
  • 49
  • 192
  • 260
deadkarma
  • 3,144
  • 2
  • 17
  • 19
176

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.

Rails 5 added or, so this is easier now in an app with Rails version greater than 5:

Model.where(column: value).or(Model.where(other_column: other_value)

this handles nil values as well

rubyprince
  • 17,559
  • 11
  • 64
  • 104
  • 44
    Even if there's raw sql — this statement looks much clearer for me than Arel. Maybe even DRYer. – jibiel Sep 30 '11 at 15:10
  • 10
    if you need to chain, other table joins which might have the columns with same column names, you should use it like this, `Page.where("pages.column = ? or pages.other_column = ?", value, other_value)` – rubyprince Dec 24 '12 at 07:36
  • 3
    And that fails if the query aliases the tables. That's when arel shines. – DGM May 08 '14 at 03:24
  • 1
    This solution will not work if you check columns which has nil value – Ganesh Sagare Mar 25 '21 at 11:18
  • 1
    @GaneshSagare yes, the sql query should be `column IS NULL or other_column IS NULL` in that case. I think Rails provide an intermediate method for getting sql fragments (where_clause something like that), let me dig it up. That might be useful here. – rubyprince Jun 08 '21 at 16:39
  • This would have worked before: `Model.where({column: value, other_column: other_value}.map { |k, v| Model.sanitize_sql_hash_for_conditions(k => v) }.join(" OR "))` but sanitize_sql_hash_for_conditions is deprecated from Rails 4.9 – rubyprince Oct 25 '22 at 11:25
115

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%'))
Dan McNevin
  • 22,278
  • 5
  • 35
  • 28
  • Feels a little messy, but at least I'm not writing sql, which just feels wrong! I'm going to have to look into using Arel more. – pho3nixf1re Sep 05 '10 at 17:34
  • The great thing is that you don't have to do it all at once, you can build up queries and it won't actually hit the database until you actually need the data. This example was just combined for brevity. – Dan McNevin Sep 05 '10 at 23:05
  • 66
    I can't beleave how much more elegant Sequel is – Macario Apr 12 '11 at 20:24
  • 3
    There is nothing wrong with SQL. The thing that can go wrong is how we build the SQL string namely [SQL Injection](http://en.wikipedia.org/wiki/SQL_injection). So, we will have to sanitize the user input before providing it to a SQL query that has to be run against the database. This will be handled by [ORM](http://en.wikipedia.org/wiki/Object-relational_mapping)s, and these have been handling the edge cases, that we tend to miss. So, it is always advisable to use [ORM](http://en.wikipedia.org/wiki/Object-relational_mapping) to create SQL queries. – rubyprince Nov 27 '14 at 11:50
  • 7
    Another problem with SQL is that it's not database agnostic. For example `matches` will produce `LIKE` for sqlite (case insensitive by default) and `ILIKE` on postgres (needs explicit case insensitive like operator). – amoebe Feb 05 '15 at 21:40
  • SQL is however demonstrably faster, if you remove all that extra fluff and go straight for the DB then you'll be more performant - OK, you'll have to handle stuff like security and platforms yourself, but this trade-off will be considerable if you're dealing with massive tables or really frequent queries – Toni Leigh Oct 22 '15 at 13:27
  • 2
    @ToniLeigh ActiveRecord is using SQL under the hood. It is just a syntax for writing SQL queries which handles SQL sanitization and make your queries DB agnostic. The only overhead is where Rails converts the syntax to SQL query. And it is just a matter of milliseconds. Ofcourse you should write the best performant SQL query and try to convert it to ActiveRecord syntax. If the SQL cannot be represented in ActiveRecord syntax, then you should go for plain SQL. – rubyprince Apr 20 '16 at 06:04
  • a millisecond or two on something your doing 100 times a second is significant - it's an option, in unusual circumstances – Toni Leigh Apr 20 '16 at 06:36
  • @ToniLeigh yeah, if you dont care about the benefits of the ORM, you can go full SQL. The issue is it will be complex to maintain, you will have to escape any user inputs (sanitize) everytime etc. It has some performance hit, but in my opinion is worth it. – rubyprince Aug 24 '20 at 19:23
73

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

Christian Fazzini
  • 19,613
  • 21
  • 110
  • 215
  • 4
    `or` is available now Rails 5 but not to implemented this way because it expects 1 argument to be passed. It expects an Arel object. See the accepted answer – El'Magnifico May 04 '17 at 16:34
  • 2
    The `or` method in ActiveRecord works if you're using it directly: but can break your expectations if it's used in a scope which is then chained. – Jeremy List Jul 17 '18 at 03:48
  • What @JeremyList said is spot on. That bit me hard. – courtsimas Sep 20 '18 at 19:09
42

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)
Greg Olsen
  • 1,370
  • 17
  • 28
26

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'))
Santhosh
  • 28,097
  • 9
  • 82
  • 87
15

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.

Rafał Cieślak
  • 972
  • 1
  • 8
  • 25
7

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}
Duke
  • 7,070
  • 3
  • 38
  • 28
5

Just add an OR in the conditions

Model.find(:all, :conditions => ["column = ? OR other_column = ?",value, other_value])
Toby Hede
  • 36,755
  • 28
  • 133
  • 162
4

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
itsnikolay
  • 17,415
  • 4
  • 65
  • 64
4

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)
khiav reoy
  • 1,373
  • 13
  • 14
3

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.

Woahdae
  • 4,951
  • 2
  • 28
  • 26
-4

Using the activerecord_any_of gem, you can write

Book.where.any_of(Book.where(:author => 'Poe'), Book.where(:author => 'Hemingway')
New Alexandria
  • 6,951
  • 4
  • 57
  • 77
-4

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.