Skip to content

Feature Request: Need to chain LEFT OUTER JOIN onto previous INNER JOIN #34325

@CharlesMcMillan

Description

@CharlesMcMillan

Setup/Demonstration

I need the ability to chain a LEFT OUTER JOIN onto an INNER JOIN...see the example to demonstrate

# frozen_string_literal: true

begin
  require "bundler/inline"
rescue LoadError => e
  $stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler"
  raise e
end

gemfile(true) do
  source "https://rubygems.org"

  git_source(:github) { |repo| "https://github.com/#{repo}.git" }

  # Activate the gem you are reporting the issue against.
  gem "activerecord", "5.0.7"
  gem "pg"
end

require "active_record"
require "minitest/autorun"
require "logger"

# Ensure backward compatibility with minitest 4.
Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test)

# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(adapter: "postgresql", prepared_statements: false)
ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do
  create_table :posts, force: true do |t|
    t.integer :user_id
  end

  create_table :users, force: true do |t|
  end

  create_table :photos, force: true do |t|
    t.integer :user_id
  end
end

class Post < ActiveRecord::Base
  belongs_to :user
end

class User < ActiveRecord::Base
  has_many :posts
  has_many :photos
end

class Photo < ActiveRecord::Base
  belongs_to :user
end

class BugTest < Minitest::Test
  def test_association_stuff
    user = User.create!
    post = Post.create!(user_id: user.id)
    photo = Photo.create!(user_id: user.id)

    photos = Photo.joins(:user).left_joins(user: :posts)
    puts Photo.joins(:user).left_joins(user: :posts).to_sql
    assert_equal 1, photos.length
  end
end

Observed Behavior (for the above example)

Note that the above errors out for v5.0.7 with a duplicate alias error, since we are calling joins and then left_outer_joins on the same table. In Rails 4.2, we actually used the other_joins gem (which we thought would be forwards compatible, but we are finding some differences) which would have produced the SQL we desire:

SELECT "photos".*
FROM "photos"
INNER JOIN "users" ON "users"."id" = "photos"."user_id"
LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"

Feature Request

Whereas with the current left_joins in Rails 5.0, we're not finding any way to get that LEFT OUTER JOIN on 'posts' to be chained onto the INNER JOIN of 'users'

Is there any way to get this behavior in the SQL quote above?

System configuration

Rails version:
5.0.7
Ruby version:
ruby 2.4.3p205

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions