-
Notifications
You must be signed in to change notification settings - Fork 51
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
Breaks with Rails 5.2.1 #97
Comments
In Polyamorous is absorbed to Ransack, and original Polyamorous won't maintain... In Polyamorous's README
|
It sseems like it would be easy to work around Polyamorous not being maintained (for now) by requiring Ransack instead, right? That's not the only problem. The join_dependency gem also doesn't work in 5.2.1, although I have a pending PR to fix that problem: rzane/join_dependency#2 |
It seems even fixing both the Polyamorous requirements and the join_dependency gem, problems still remain. Running the tests gives me:
As well as several situations where baby_squeel expects there to be a |
I stumbled upon this issue after trying to migrate my application from Rails 4 to 5.2.1. Whew, having polyamorous not being maintained anymore (pulled into ransack), is pretty tough. I noticed that @rzane created an issue in polyamorous back in March adressing this (activerecord-hackery/polyamorous#38), but there hasn't been any response yet. That project looks dead to me. @rzane Any plans on how to proceed? Pulling polyamorous (or the fixed code from within ransack) into baby_squeel or join_dependency? I'm currently at the point of going back to Rails std query interface with arel. I do like baby_squeel very much, but would like to have a way forward pretty soon. |
Yeah, this is definitely a setback. I think I would most likely move the polyamorous codebase into join_dependency. Or, if it's possible and easier, just depend on ransack. |
Any more recent updates on this? |
Okay, so I started digging in here. Polyamorous becoming part of Ransack is inconvenient, but not a dealbreaker. Baby Squeel can simply depend on Ransack in order to bring in Polyamorous. However, it really sucks when this library breaks when Active Record changes. And, digging through the Active Record source code, duplicating private Active Record functionality isn't very future proof. So, I'm proposing a change to Baby Squeel that I hope will remove this problem. Basically, 99% of the complexity comes from predicting a table alias. It's a cool feature, but I don't think it's worth the maintenance effort or the lack of reliability. When the same table is hit twice in the same query, Active Record will automatically create an alias for that table. In the example below, see the posts table is joined as irb> Post.joins(author: :posts).where.has { author.posts.id > 0 }
SELECT "posts".* FROM "posts"
INNER JOIN "authors" ON "authors"."id" = "posts"."author_id"
INNER JOIN "posts" "posts_authors" ON "posts_authors"."author_id" = "authors"."id"
WHERE "posts_authors"."id" > 0 In the example above, Baby Squeel had to figure out that > Post.joins(author: :posts).where.has { author.posts.as('posts_authors').id > 0 } I'm going to release a new minor version that will give you a deprecation warning in any scenario where the "automatic aliasing" kicked in. It'll describe exact steps for how you can remedy your code. Once that's released, I'm going to release Baby Squeel 2.0. This version should be able to support 5.2.1 and won't automatically predict aliases anymore. |
To me, that was of the main benefits of Baby Squeel. Preloaded associations are straightforward enough but eager loaded association aliases are hard to predict. My opinion isn't worth too much though, I've just left the company where I was using Baby Squeel. |
As @chewi outlines, predicting eager loaded association aliases is difficult and is the reason I pull baby_squeel into a project. I'm probably in the minority, but it's the only functionality I care about that is provided by the gem. The complexity you outline is real though and if the primary audience of this gem doesn't rely on the feature, it makes sense to remove this functionality. |
We introduced baby_squeel because we have a lot of complex queries which were mostly written in plain SQL. Transforming them to plain ActiveRecord Relations was simply not possible and using Arel was far too complex for such huge queries. baby_squeel does this now for us and we are quite happy 🎉 Loosing one of the main features of baby_squeel is really a setback - but understandable 😞 @rzane i am willing to help if you have some ideas, because we rely on this awesome gem! |
Yeah, I'm revisiting my previous statements. Now that ransack has to be a dependency, we might be able to take advantage of how they resolve the aliases. Since Ransack is pretty actively maintained, this would allow us greater reliability. I don't have a lot of time right now, so I would love it if somebody would step up and try to achieve this. I can push up a branch of what I currently have soon. |
I forked the polyamorous gem and integrated the latest updates from the ransack gem. This is currently working for me on rails 5.2.1.1, although I am not using a lot of the baby_squeel features. https://github.com/vintrepid/polyamorous And in my Gemfile: gem 'polyamorous', "~> 1.3.4", git: 'https://github.com/vintrepid/polyamorous.git' |
Hi @vintrepid , |
@wollistik is right. I was able to get polyamorous back by bringing in Ransack as a dependency, but once I did that, all of the tests were failing for 5.2 because it would use inner join instead of left join. I'd like to be able to isolate the problem, because I'm not 100% certain whether it's a problem with baby_squeel's usage of polyamorous or with polyamorous itself. |
Polyamorous was absorbed into Ransack as we are trying to simplify the support, and the general policy of Ransack has been to drop older versions of Rails. There are 3 options here:
In my mind #3 is the best for code reuse, but it will also require the most work to maintain, esp. as Baby Squeel and Ransack have different support policies for older Rails versions. On the other hand if we join forces we could pool our programming time better. As an extension of option 3, we could push common functionality out of both Ransack and Baby Squeel into a Polyamorous+ Thoughts @gregmolnar, @rzane ? |
Thanks for chiming in @seanfcarroll. I think bringing polyamorous into Ransack made sense for the following reasons:
My opinion here is that option #1 is certainly not ideal, but doable. The situation that I'm afraid of here would be the reliance on Ransack's test suite to ensure that Polyamorous still works, which I suspect might be currently happening. As a result, I'm afraid that Polyamorous might not be doing what it's supposed to be doing, but it's really hard for me to demonstrate that. Option #2 seems like it would be a disaster. The problem there is that if someone were to install Ransack and Baby Squeel, we'd patch Active Record twice? Plus, the obvious maintenance burden. Option #3 sounds really great to me. But, I don't want to make Ransack harder to maintain. There were reasons that polyamorous was brought into Ransack. Maybe Polyamorous could stay in the Ransack repo, but it would exist as a separate gem? Then, you could test/version it alongside Ransack. This is basically what Rails does. From there, we could work on improving the tests and documentation for Polyamorous. Polyamorous previously had a few unit tests, but I don't think they were very effective in preventing regression. I think we need some higher level tests that actually assert on the resulting SQL, which has been a pretty effective strategy for Baby Squeel. I definitely think there is a lot of overlap between Ransack and Baby Squeel, specifically in resolving aliases that never lived in Polyamorous, but probably could have. It would be really great to work together in order to make both Ransack and Baby Squeel simpler and easier to maintain. |
I think having polyamorous as a gem living in the same repo would be the easiest thing to do. |
@rzane One thing we should iron out is, we are supporting different versions of Active Record. In ransack, we don't really want to support any non-supported version of Active Record(and I mean full support, not security patches) because it is just too much extra work and hopefully it will make more people be on recent versions. Of course, as long as it doesn't mean any extra work, we will depend > 5, but if it takes too much effort to make something work for an unsupported version, we will raise the dependency probably. As far as I see baby squeel seeems to support > 4.2.
You could first depend on polyamorous 2.2, then later or decide whether you want to stay on that, or follow the same policy as we do and jump on 3.0. /cc @seanfcarroll |
Great to see all of this engagement. Keeping Polyamorous as it's own gem inside Ransack works for me. @gregmolnar 's point about aligning versions is a good one. Rails versions are moving pretty fast these days, and I think it is a fair policy for an open source project to support the currently supported Ruby & Rails versions only. It would be a different story if there were many PRs to these projects, but in fact there are few and additionally the Ransack codebase needs a cleanup. It is always possible to lock an older app to an older version of the gem. I really like Baby Squeel - it's a great gem, I am going to start using it in my projects. |
Yeah, that works for me. I'm don't expect too many new features, and as such, I have no qualms about only supporting one Active Record version at a time. |
@rzane sorry, not really following the final approach, is it possible to have |
@vitalinfo for now you need to add |
@gregmolnar unfortunately it doesn't work for me
|
Bummer. You can try this #97 (comment) or wait till we make it properly work, but I can't promise a date for that. |
@gregmolnar tried hour ago with the same result |
@gregmolnar just an experiment have changed
and it works, but why doesn't work original implementation will investigate in the nearest days |
FWIW, I got this working with a mixture of these suggestions.
|
As I understand |
Hmm, I just tried the ar-521, I can not manage to install the polyamorous gem... It tells me:
And I could indeed not find polyamorous version with tag 2.1.1 Did I do something wrong? |
@Arpsara You can get latest polyamorous from ransack and then use git 'https://github.com/activerecord-hackery/ransack', branch: 'master' do
gem 'polyamorous'
end
gem 'baby_squeel', github: 'rzane/baby_squeel', branch: 'ar-521 |
This doesn't seem to be working for me. I get the same error that @Arpsara was getting. I've tried using tag |
@typhoon2099 polyamorous is released separately now, so you can just try:
|
Using the following:
gives me the following:
|
@typhoon2099 you need to bump the dependency version in baby squeel in that branch. Maybe @rzane has time to sort that, but I am sure he would be happy to accept a PR handling it. |
Ah, okay, I misunderstood the workaround above. |
Disclaimer: Active Record >= 5.2.1 is currently broken. While the If this was simply a matter of updating dependencies, I would have released a new version. There are numerous test failures on that branch, all stemming from the inability to locate the correct alias for a table. Unfortunately, I don't have the time right now to dig in and figure out what is causing those issues. This is the line that is causing all of the problems. I would really appreciate help figuring out what the issue is. |
This may not be a solution for everyone but we found that we only used baby_squeel for a few things and I found some ways to have a decent syntax without it... Most of our queries that used it were simple greater than or less then. I created an extension that could help like this. module QueryExtensions
extend ActiveSupport::Concern
included do
scope :where_gt, ->(column, value) { where("#{column} > ?", value) }
scope :where_gte, ->(column, value) { where("#{column} >= ?", value) }
scope :where_lt, ->(column, value) { where("#{column} < ?", value) }
scope :where_lte, ->(column, value) { where("#{column} <= ?", value) }
end
end Then I included in my ApplicationRecord class that all my models inherit from. class ApplicationRecord < ActiveRecord::Base
include QueryExtensions
end This allowed us to convert queries that were like this User.where.has { created_at > 10.days.ago } to
And for joining we just used standard joins or left_joins depending on if it was outer or not. c = customer # Needed for name conflict
GiftCard
.joining { customer }
.where.has {
(customer.id == c.id) | (phone == c.phone)
} To something like query = GiftCard.joins(:customer)
query.where(gift_cards: { customers: { id: customer.id } })
.or(query.where(gift_cards: { phone: customer.phone })) Depending on how deeply embedded baby_squeel is in your application this may not be an option. The downside is that the queries are a little harder to read in my opinion but with active record '.or' and '.merge' you can get most things working without use of Arel tables. Also, the column names are not escaped but since this is not dynamic data passed in from user in our case should not be much of a problem |
Hey @gregpardo, I'm glad you found a simple solution. If BabySqueel didn't have to worry about joins, it would actually be incredibly simple. Here's what that would look like in just 45 lines of code: https://gist.github.com/rzane/8104af09369fbce3d2776c4a194e1de6 |
@rzane Thanks thats actually pretty handy and looks more flexible than what I came up with. Will keep this in mind and hopefully it can help others. |
I'm having a look at this issue and found that baby_squeel started breaking after this rails commit: rails/rails@50036e6
@tables and @alias_tracker instance variables, resulting in a nil table as said by @rzane.
I have no idea how to solve this yet, if anyone can look that commit and give some help. |
The I raised errors on this line on baby_squeel
And this line on activerecord https://github.com/rails/rails/blob/7b5cc5a5dfcf38522be0a4b5daa97c5b2ba26c20/activerecord/lib/active_record/associations/join_dependency/join_association.rb#L58 And this is the diff in the backtrace https://gist.github.com/tiagoefmoraes/e2319a75f82bdc136e2d95cf1cf01143/revisions?diff=split#diff-f80222de64b3079c261e058703f4e07a |
My team is just running into this issue now, too. I'm wondering if BabySqueel might just force aliases on associations (and track the ones it creates) rather than trying to discover the aliases assigned dynamically by ActiveRecord? I'd be willing to help with the implementation if this seems like a viable solution. |
@rtweeks, that would be a viable solution and would massively decrease the complexity of this library. Happy to accept pull requests! |
This may help with rzane#97.
I found a quick way to fix a lot of the broken tests (about 10 of them) by directing Active Record's |
I think the polymorphism issues are because
The output string here should include a ActiveRecord 5.2.0 also shows this behavior (I happen to have a VM with that version lying around), so this is not new to AR >= 5.2.1. |
By the same token, inner- and outer-joins seem to be getting confused by the
@gregmolnar and team, this is not intended in any to bash |
If I use the master branch (commit c9cc20de9e) of Ransack for Polyamorous, I've got it down to 2 errors from the unit tests -- the ones about
|
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.
I just opened PR #109 for this. |
I think this issue is fixed in |
* 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]>
Issue
With latest Rails 5.2.1 baby_squeel breaks.
Reproduction
The text was updated successfully, but these errors were encountered: