Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ActiveRecord fails to include models given on a particular order after a join #30603

Closed
clemoberti opened this issue Sep 14, 2017 · 8 comments
Closed

Comments

@clemoberti
Copy link

clemoberti commented Sep 14, 2017

Steps to reproduce

Setup

I have three models

# models/profile_translation.rb
class ProfileTranslation < ApplicationRecord
  belongs_to :profile
  has_one :user, through: :profile
end

# models/profile.rb
class Profile < ApplicationRecord
  belongs_to :user
  has_many :profile_translations, foreign_key: 'profile_id'
end

# models/user.rb
class User < ApplicationRecord
  has_one :profile
  has_many :profile_translations, through: :profile
end

Query

This query (which looks silly but seems valid to me) is to simplify a much bigger example.

ProfileTranslation.joins(:profile).includes(:user, :profile)

Expected behavior

I would expect to get an ActiveRecord::Relation of ProfileTranslations along with their user and profile.

Actual behavior

PG::UndefinedTable: ERROR:  missing FROM-clause entry for table "profiles_profile_translations"...

The interesting part is that if I change the order or the included elements:

ProfileTranslation.joins(:profile).includes(:profile, :user)

Then I get my expected result.

System configuration

Rails version:
gem 'rails', '~> 5.1.4'

Ruby version:
ruby '2.4.1'

@clemoberti clemoberti changed the title Active record bug with joins and includes ActiveRecord (bug?) with joins and includes Sep 14, 2017
@kamipo
Copy link
Member

kamipo commented Sep 17, 2017

Can you provide an executable test script using this template?

@Bartuz
Copy link

Bartuz commented Sep 24, 2017

Couldn't recreate the issue. Here is my executable test script, @kamipo ,

https://gist.github.com/Bartuz/175845efab2ab3f3bc6b808cced7f571

@clemthenem , are you sure it isn't something about your applicationRecord?

@houhoulis
Copy link
Contributor

@Bartuz , the reason your script did not replicate the issue is because your code creates a query but doesn't execute it. If you append a ruby command like "map(&:id)" to the end of your query, then it does reproduce the error.

@houhoulis
Copy link
Contributor

houhoulis commented Oct 16, 2017

Using ruby 2.4.2, I was able to replicate the behavior that @clemthenem described by using @Bartuz 's script with ".map(&:class)" appended to the query. I observed different error messages when using the 'pg' gem vs. the 'sqlite3' gem: "PG::UndefinedTable: ERROR: missing FROM-clause entry for table 'profiles_profile_translations'" vs "SQLite3::SQLException: no such column: profiles_profile_translations.id". But both cases logged the same generated SQL to stdout:

> ProfileTranslation.joins(:profile).includes(:user, :profile).map(&:class)
SELECT "profile_translations"."id" AS t0_r0, "profile_translations"."profile_id" AS t0_r1,
  "users"."id" AS t1_r0, "profiles_profile_translations"."id" AS t2_r0,
  "profiles_profile_translations"."user_id" AS t2_r1
  FROM "profile_translations"
  INNER JOIN "profiles" ON "profiles"."id" = "profile_translations"."profile_id"
  LEFT OUTER JOIN "profiles" "profiles_profile_translations_join"
    ON "profiles_profile_translations_join"."id" = "profile_translations"."profile_id"
  LEFT OUTER JOIN "users"
    ON "users"."id" = "profiles_profile_translations_join"."user_id"

And the contrasting example did produce SQL without the phantom table:

> ProfileTranslation.joins(:profile).includes(:profile, :user).map(&:class)
SELECT "profile_translations"."id" AS t0_r0, "profile_translations"."profile_id" AS t0_r1,
  "profiles"."id" AS t1_r0, "profiles"."user_id" AS t1_r1, "users"."id" AS t2_r0
  FROM "profile_translations"
  INNER JOIN "profiles" ON "profiles"."id" = "profile_translations"."profile_id"
  LEFT OUTER JOIN "profiles" "profiles_profile_translations_join"
    ON "profiles_profile_translations_join"."id" = "profile_translations"."profile_id"
  LEFT OUTER JOIN "users"
    ON "users"."id" = "profiles_profile_translations_join"."user_id"

I don't know enough to evaluate @clemthenem 's symptoms, nor whether the example is well-formed.

@kamipo kamipo self-assigned this Oct 20, 2017
@clemoberti
Copy link
Author

Hi guys,
Thanks a lot @Bartuz and @houhoulis for your time replicating the issue, I apologise for not replying earlier... The example is well formed yes, that's exactly what happened to me. Let me know if you need any extra info @kamipo and thank you so much for your help!

@clemoberti clemoberti changed the title ActiveRecord (bug?) with joins and includes ActiveRecord fails to include models given on a particular order after a join Jan 19, 2018
@rails-bot rails-bot bot added the stale label Apr 19, 2018
@rails-bot
Copy link

rails-bot bot commented Apr 19, 2018

This issue has been automatically marked as stale because it has not been commented on for at least three months.
The resources of the Rails team are limited, and so we are asking for your help.
If you can still reproduce this error on the 5-1-stable branch or on master, please reply with all of the information you have about it in order to keep the issue open.
Thank you for all your contributions.

@kamipo kamipo added pinned and removed stale labels Apr 23, 2018
@kamipo kamipo closed this as completed in 15e3e9c Jun 19, 2018
kamipo added a commit that referenced this issue Jun 19, 2018
…ucted

Currently, column aliases which is used for eager loading are calculated
before constructing all table aliases in FROM clause.

`JoinDependency#join_constraints` constructs table aliases for `joins`
first, and then always re-constructs table aliases for eager loading.

If both `joins` and eager loading are given a same table association,
the re-construction would cause the discrepancy between column aliases
and table aliases.

To avoid the discrepancy, the column aliases should be calculated after
all table aliases are constructed.

Fixes #30603.
@ziaulrehman40
Copy link

Was this fix released in rails 4 line or only 5.1.x, i am sorry not sure how to check that.

@kamipo
Copy link
Member

kamipo commented Oct 24, 2018

This is fixed in master, and backported to 5-2-stable in 50036e6.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants