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

fix polymorphic joins with rails > 5.2 #1004

Merged

Conversation

gregmolnar
Copy link
Member

@gregmolnar gregmolnar commented Feb 12, 2019

closes #996 and #902 and #955
I still need to add some specs to cover this.

@dholdren
Copy link

I was able to confirm that this solves my issue. Thanks again.

rzane added a commit to rzane/baby_squeel that referenced this pull request Feb 17, 2019
one polymorphism test is fixed.

There are still several failures. Basically, any test that does an outer
join is still doing an inner join.
rzane added a commit to rzane/baby_squeel that referenced this pull request Feb 17, 2019
one polymorphism test is fixed.

There are still several failures. Basically, any test that does an outer
join is still doing an inner join.
rzane added a commit to rzane/baby_squeel that referenced this pull request Feb 17, 2019
one polymorphism test is fixed.

There are still several failures. Basically, any test that does an outer
join is still doing an inner join.
@rzane
Copy link
Contributor

rzane commented Feb 17, 2019

@gregmolnar, I just ran this against baby_squeel's test suite (branch here, results here).

It seems like this does fix #902 and #955, so great work. It fixed all of the tests that were specifically related to polymorphism. Those tests had been broken in baby_squeel since Active Record 5.2 initially came out.

However, #955 seems to be in play still. You'll notice that some of the tests that should say LEFT JOIN are instead saying INNER JOIN.

The branch also includes this change as a workaround for the fact that JoinAssociation#table seems to be returning nil sometimes. The change seems to fix most of the tests, but I suspect that it might be covering up a larger issue. I suspect that the workaround is also causing the test failures that are reporting the wrong table alias. Maybe this is a clue?

@gregmolnar
Copy link
Member Author

@rzane Thanks for the info. I need to find a few hours block when I go over again this and find the root cause.

@kieranklaassen
Copy link

Thanks, guys for the work on this! I would really appreciate it if you can merge this one @gregmolnar .

@gregmolnar
Copy link
Member Author

@kieranklaassen the trouble is the fix on this branch causes issues if you use left_joins in you app. I know what causes the problem and have a rough idea of a fix, just need to find the time when I can sit down for a few hours and get it done. Hopefully I will manage to get there soon.

@kieranklaassen
Copy link

@gregmolnar I appreciate your efforts very much!! If you do not have time but could share your idea for the fix I might be able to help out here too. Thanks!

@pelletencate
Copy link

pelletencate commented Apr 8, 2019

@gregmolnar I'd love to help out here too. We ourselves depend on baby_squeel, and it'd be awesome if I can be of assistance in speeding up this process a bit. If it's easier / less time consuming for you to do a brain-dump here, I'm more than happy to try and give it a go!

@gregmolnar
Copy link
Member Author

I need to get into the code to get my head around the problem again to be able to make a brain-dump and I will probably just fix it if I manage to get there.
On a very high level, the issue is we used to override ActiveRecord::Associations::JoinDependency#make_left_outer_joins, but that is either removed on Rails 5.2, or we thought we don't need to override it anymore(I can't remember) but we still need a workaround to turn our joins into a left one. Beware, I am writing this without checking the codebase, but this is roughly where I remember to look where debugged this issue.

@gregmolnar
Copy link
Member Author

gregmolnar commented Apr 14, 2019

I finally managed to work on this and I think it is fixed now, although I couldn't come up with specs so far.
Could you please guys verify that it works for you?
@rzane I ran the specs in your branch and some still fails, but those failures might be unrelated? I don't know much about baby_squeel, but it looks like the issue happens with some aliasing.

@gregmolnar
Copy link
Member Author

@rzane Actually, those alias errors looks like caused by ransack too, and there is a PR to fix that: https://github.com/activerecord-hackery/ransack/pull/1005/files
I will merge this first if I get the feedback of it being ok, then will merge that too.

@rzane
Copy link
Contributor

rzane commented Apr 15, 2019

Thanks again for digging into this @gregmolnar.

It seems like once a relation starts to do any outer join, all subsequent joins become outer joins? Take this example:

Post.joining { author.outer.comments }

In the example above, I would expect posts -> author to be an outer join and author -> comments to be an inner join. In previous Active Record versions, that works as expected. But, that's not what is happening on 5.2.1. Here's the failing spec:

expected:
        SELECT "posts".* FROM "posts"
        LEFT OUTER JOIN "authors" ON "authors"."id" = "posts"."author_id"
        INNER JOIN "comments" ON "comments"."author_id" = "authors"."id"
     got:
        SELECT "posts".* FROM "posts"
        LEFT OUTER JOIN "authors" ON "authors"."id" = "posts"."author_id"
        LEFT OUTER JOIN "comments" ON "comments"."author_id" = "authors"."id"

Another issue is the alias detection. Here's a gist of what that looks like in Baby Squeel.

def find_alias(associations)
   join_association = find_join_association(associations)
   join_association.table
end

Baby Squeel is successfully finding the correct JoinAssociation. On previous versions of Active Record, #table would return an Arel::Table with the correct name. However, when running against 5.2.1, #table is nil. I'm honestly not sure if this part is a polyamorous issue or a baby_squeel issue caused by a change in Active Record.

@gregmolnar gregmolnar merged commit 5170f73 into activerecord-hackery:master May 11, 2019
@gregmolnar
Copy link
Member Author

I merged this, since it fixes most of the issues and I want to make master work with Rails 6. I will open a follow up issue for the remaining issue.

graywolf1138 added a commit to TheTalentEnterprise/baby_squeel that referenced this pull request Sep 6, 2022
* Find the table

* Use polyamorous from master

* With activerecord-hackery/ransack#1004, all but
one polymorphism test is fixed.

There are still several failures. Basically, any test that does an outer
join is still doing an inner join.

* Explain how this is completely broken

* Add byebug for development/testing

* Have Active Record build tables for their aliases

This may help with rzane#97.

* Fix test for equivalent logic

The new version of Active Record or Polyamorous seems to switch the
order of these two SQL conditions, but the new statement is logically
equivalent to the old one.

* Use `variants` for SQL snapshot change

* Make it possible to get good polymorphic joins

Actually getting polymorphic joins to work correctly will require
either explicitly specifying the master branch of the `ransack`
project (commit c9cc20de9e0f or something with equivalent
functionality) in the project `Gemfile` or the `ransack` project
releasing a new 2.x (> 2.3.2) version with that functionality.

Addresses most of the Active Record 5.2.x (>= 5.2.1) problems in
rzane#97.  The only remaining issues are around inner
joins after left joins.

* Track all associations used to find correct alias

By tracking the associations accumulated within an expression, we
can best even Active Record's own `#where` method's ability to
correctly set conditions on column values via associations.

* Reimplement #find_join_association iteratively

Replacing recursive method calls with plain iteration is almost
certainly more performant.

* Revert unnecessary changes from commit 90e02e2

* Lock down the supported versions of ActiveRecord

* Update rspec, rake, and sqlite3

* Run against Ruby 2.6

* Drop support for Active Record versions that have reached EOL

* Remove old variants

* Remove broken image from the readme

* Install latest bundler

* Explicit require test dependencies

* Remove filewatcher

* Run on GitHub actions

* Require coveralls

* Run as a matrix

* Share the environment variables

* Use the coveralls action

* Not sure what is going on here...

* Run against 5.2.0 and 5.2.5

* Give each job a name

* Remove coverage

* Mark failing tests as pending

* Get 5.2.0 passing again

* Remove coverage

* Bump

* Merge `join_dependency` back into this project, because my dreams did not really come true

* Fix checking for version as string

* Add changes from 1.4.0.beta1 to CHANGELOG.md

* Build pull requests

* remove old code from activerecord < 5.2

* removed BabySqueel::Pluck

* reduce complexety after merging `join_dependency` back into this project

* Fix table alias when joining a polymorphic table twice (rzane#108)

* Update changelog for v1.4.0

* Bump version to v1.4.0

* Tidy up version comparison code

* Bump version to v1.4.1

* add support for activerecord 6.0

* add support for activerecord 6.1

* speed up BabySqueel::ActiveRecord::VersionHelper

* add support for activerecord 7.0

* update .github/workflows/build.yml to test rails 7.0 and ruby 3.0 / 3.1

* Apply version-specific monkey-patches outside of the method definition

* Update changelog for v1.4.2

* v1.4.2

* ISSUE-117: left_joins performs INNER JOIN with ActiveRecord 6.1.4.4

* Update changelog for 1.4.3 release

* Bump to v1.4.3

* ISSUE-119: Nested merge-joins query causes NoMethodError with ActiveRecord 6.1.4.4 rzane#119

* Prepare v1.4.4

* ISSUE-121: Drop support for ActiveRecord older than 6.0

* AR 6.1: fix - FrozenError: can't modify frozen object: []

* Bump v2.0.0

Co-authored-by: Ray Zane <[email protected]>
Co-authored-by: Richard Weeks <[email protected]>
Co-authored-by: Jonas S <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

AR 5.2.1 and 5.2.2 transitive polymorphic association results in INNER JOIN which breaks "or" searches
6 participants