Squeel to execute outer join on Rails
-
29-10-2019 - |
Question
I'm trying to find a way to create a simple outer join without too much hassle. I know I can do this manually by specifying an outer join, but I'm looking for a simple way.
Therefore, I was taking a look at Squeel, which seems to be the new alternative for Metawhere. It seems to be able to handle outer joins, but I can't get what I want.
In particular, I have three models :
City
Building
CityBuilding
I would simply like a list of all the buildings whether they exist in a city or not. CityBuilding is, of course, the model that connects a city to a building. I would like to get something like :
city 1{
TownCenter => city_building
Sawmill => city_building
Quarry => nil
}
The query is null since there is no city_building
entry for this one, you get the idea.
Is there a way that Squeel does that? Or maybe another gem, without having to manually do an outer join?
Solution
I think you can try something like the below using Squeel. I am not sure about the where part. You will have to give one of the two join conditions.
Building.joins{city}.joins(city_buildings.outer).where{(buidlings.id == city_buildings.building_id) & (cities.id == city_buildings.city_id)}
or
Building.joins{city}.joins(city_buildings.outer).where{buidlings.id == city_buildings.building_id}
or
Building.joins{city}.joins(city_buildings.outer).where{cities.id == city_buildings.city_id}
OTHER TIPS
The AR association includes
uses LEFT OUTER JOIN
. If you have a model relationship as follows, then:
class City
has_many :city_buildings
has_many :buildings, :through => :city_buildings
end
class Building
has_one :city_building
has_one :city, :through => :city_building
end
class CityBuilding
belongs_to :city
belongs_to :building
end
To get a list of buildings regardless of city link
Building.includes(:city).where(...)
To get a list of buildings with a of city link
Building.includes(:city).where("cities.id IS NOT NULL")
Note
I am assuming you want to access the city object after the query(if present).
This is not a good solution if you DO NOT want to eager load the city object associated with a building (as AR eager loads include associations after executing the OUTER JOIN).