Search code examples
sqlruby-on-railsrubyruby-on-rails-3arel

How to properly add brackets to SQL queries with 'or' and 'and' clauses by using Arel?


I am using Ruby on Rails 3.2.2 and I would like to generate the following SQL query:

SELECT `articles`.* FROM `articles` WHERE (`articles`.`user_id` = 1 OR `articles`.`status` = 'published' OR (`articles`.`status` = 'temp' AND `articles`.`user_id` IN (10, 11, 12, <...>))) 

By using Arel this way

Article
 .where(
   arel_table[:user_id].eq(1)
   .or(arel_table[:status].eq("published"))
   .or(
     arel_table[:status].eq("temp")
     .and(
       arel_table[:user_id].in(10, 11, 12, <...>)
     )
  )
)

it generates the following (note: brackets are not the same as the first SQL query):

SELECT `articles`.* FROM `articles` WHERE (((`articles`.`user_id` = 1 OR `articles`.`status` = 'published') OR `articles`.`status` = 'temp' AND `articles`.`user_id` IN (10, 11, 12, <...>))) 

Since I think the latter SQL query doesn't "work" as the first one, how could I use Arel (or, maybe, something else) so to generate the SQL query as the first one?

Update (after comments)

Given SQL queries above "work" the same but I still would like to generate the exact SQL query as the first one in the question (the main reason to make this is that the first SQL query is more readable than the second since in the first one are used less and "explicit" brackets), how could I make that by using Arel?


Solution

  • I've successfully used this gem: squeel which comes on top of Arel so you don't have to mess with it. So in order to generate your query you would do something like this in Squeel:

    @articles = Article.
      where{
      ( user_id.eq(1) | status.eq('published') ) |
      ( user_id.in([10, 11, 12, '<...>']) & status.eq('temp') )
    }
    
    # since this is an ActiveRecord::Relation we can play around with it
    @articles = @articles.select{ [ user_id, status ] }
    
    # and you can also inspect your SQL to see what is going to come out
    puts @articles.to_sql
    

    The more complicated your queries get the more you're going to like this gem.