Arel, Joins and Rails Queries

Jason picture Jason · Feb 22, 2011 · Viewed 15.4k times · Source

I've been stuck on a problem recently for a little while and found my way to Arel which looks like it should allow me to do OR's in my queries.

As a starting point I needed to convert an existing Rails 3 query to Arel and that's where I've run into problems.

The following scope and query works as I would expect it to. It gives me the requests associated with a particular user's ads.

#in the Request class
scope :responder, lambda { |user| joins(:ad).where(:ads => { :user_id => user }) }

Request.responder(303).to_sql

=> "SELECT \"requests\".* FROM \"requests\" INNER JOIN \"ads\" ON \"ads\".\"id\" = \"requests\".\"ad_id\" WHERE (\"ads\".\"user_id\" = 303)"

According to doco on the Arel github page and Railscast 215 I should be able to do something like the following to replicate the query with Arel

  requests = Request.arel_table
  ads = Ad.arel_table
  where(requests.join(ads).on(ads[:id].eq(requests[:ad_id])))

This results in an error

TypeError: Cannot visit Arel::SelectManager

I can do the following in the console though

r = Request.arel_table
a = Ad.arel_table

r.join(a).to_sql
 => "SELECT  FROM \"requests\" INNER JOIN \"ads\" "

So it looks like it's forming the SQL request, however when you put that in a where

Request.where(r.join(a)).to_sql

I get the following

TypeError: Cannot visit Arel::SelectManager....

I've tried doing other Arel actions within the where and it works (e.g.)

Request.where(r[:status].eq(nil)).to_sql
 => "SELECT \"requests\".* FROM \"requests\" WHERE (\"requests\".\"status\" IS NULL)"

This is a little beyond my growing rails/ruby knowledge. Any ideas?

Thanks in advance.

Answer

user1430522 picture user1430522 · Jun 1, 2012

You can use join_sources.first on Arel::SelectManager and the pass this to joins

requests = Request.arel_table
ads = Ad.arel_table
Request.joins(requests.join(ads).on(ads[:id].eq(requests[:ad_id])).join_sources.first)