According to https://www.w3schools.com/sql/sql_join.asp there are four types of joins in SQL. In fact there is also self-join and cross join but lets focus on:
INNER JOIN, LEFT (OUTER) JOIN, RIGHT (OUTER) JOIN, FULL (OUTER) JOIN.

Assume that we have following factories:

1
2
3
4
5
6
7
8
let!(:user_1) { create(:user)} # user with 2 trips
let!(:user_2) { create(:user)} # user with 1 trip
let!(:user_3) { create(:user)} # user with no trips

let!(:trip_1) { create(:trip, user: user_1) }
let!(:trip_2) { create(:trip, user: user_1) }
let!(:trip_3) { create(:trip, user: user_2) }
let!(:trip_4) { create(:trip, user: nil) } # trip with no user

1. INNER JOIN

1
2
3
4
5
6
7
8
9
10
11
12
13
14
inner_join = User.joins(:trips)
puts inner_join.to_sql
# => SELECT "users".* FROM "users" INNER JOIN "trips" ON "trips"."user_id" = "users"."id"

expect(inner_join.count).to eq(3)

inner_join.each do |user|
puts [user.id, user.trips.pluck(:id)].inspect
end

# =>
[364, [485, 486]]
[364, [485, 486]]
[365, [487]]

Keep in mind that you should use .distinct at the end of the query chain to get unique rows.

2. LEFT (OUTER) JOIN

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
left_outer_join = User.left_outer_joins(:trips) # or simply use an alias: left_joins 
puts left_outer_join.to_sql
# => SELECT "users".* FROM "users" LEFT OUTER JOIN "trips" ON "trips"."user_id" = "users"."id"

expect(left_outer_join.count).to eq(4)

left_outer_join.each do |user|
puts [user.id, user.trips.pluck(:id)].inspect
end

# =>
[367, [489, 490]]
[367, [489, 490]]
[368, [491]]
[369, []]

Possible use case of using LEFT (OUTER) JOIN:

Counting how many trips every user has:

1
2
3
4
5
6
7
query = left_outer_join
.select("users.*, COUNT(trips.*) as trips_count")
.group('users.id').count('trips.*')

puts query.inspect
# =>
{519=>0, 517=>2, 518=>1}

3. RIGHT (OUTER) JOIN

1
2
3
4
5
6
7
8
9
10
11
12
13
14
right_outer_join = User.joins('RIGHT OUTER JOIN trips ON trips.user_id = users.id')
puts right_outer_join.to_sql
# => SELECT "users".* FROM "users" RIGHT OUTER JOIN trips ON trips.user_id = users.id

expect(right_outer_join.count).to eq(4)

right_outer_join.each do |user|
puts [user.id, user.trips.pluck(:id)].inspect
end
# =>
[370, [493, 494]]
[370, [493, 494]]
[371, [495]]
[nil, [496]]

4. FULL (OUTER) JOIN

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
full_outer_join = User.joins('FULL OUTER JOIN trips ON trips.user_id = users.id')
puts full_outer_join.to_sql
# => SELECT "users".* FROM "users" FULL OUTER JOIN trips ON trips.user_id = users.id

expect(full_outer_join.count).to eq(5)

full_outer_join.each do |user|
puts [user.id, user.trips.pluck(:id)].inspect
end
# =>
[373, [497, 498]]
[373, [497, 498]]
[374, [499]]
[nil, [500]]
[375, []]