-
-
Notifications
You must be signed in to change notification settings - Fork 638
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
accessible_by
may crash when a default_scope
is used
#600
accessible_by
may crash when a default_scope
is used
#600
Conversation
If you have a `default_scope` that sets ordering, and define a permission that checks for records via multiple tables, and use a `has_many :through`, and run Postgres... then on version 3.x, `accessible_by` may crash. The attached test suite shows how; the tests that call `alex.blog_post_comments` fail with: ``` ActiveRecord::StatementInvalid: PG::InvalidColumnReference: ERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list LINE 1: ... ORDER BY "blog_post_comments"."created_at" DESC, "blog_post... ^ : SELECT DISTINCT "blog_post_comments".* FROM "blog_post_comments" INNER JOIN "blog_posts" ON "blog_post_comments"."blog_post_id" = "blog_posts"."id" LEFT OUTER JOIN "blog_posts" "blog_posts_blog_post_comments" ON "blog_posts_blog_post_comments"."id" = "blog_post_comments"."blog_post_id" LEFT OUTER JOIN "blog_authors" ON "blog_authors"."id" = "blog_posts_blog_post_comments"."blog_author_id" WHERE "blog_posts"."blog_author_id" = $1 AND "blog_authors"."id" = $2 ORDER BY "blog_post_comments"."created_at" DESC, "blog_posts"."title" ASC ``` This regressed in #512
The fixed query looks like this: ``` SELECT DISTINCT blog_post_comments.created_at AS active_record_query_fixer_0, blog_posts.title AS active_record_query_fixer_1, blog_post_comments.* FROM "blog_post_comments" INNER JOIN "blog_posts" ON "blog_post_comments"."blog_post_id" = "blog_posts"."id" LEFT OUTER JOIN "blog_posts" "blog_posts_blog_post_comments" ON "blog_posts_blog_post_comments"."id" = "blog_post_comments"."blog_post_id" LEFT OUTER JOIN "blog_authors" ON "blog_authors"."id" = "blog_posts_blog_post_comments"."blog_author_id" WHERE "blog_posts"."blog_author_id" = 1 AND "blog_authors"."id" = 1 ORDER BY "blog_post_comments"."created_at" DESC, "blog_posts"."title" ASC ``` (note extra columns in the `SELECT DISTINCT`) I'm not sure on cancancan's policy on adding extra gems, so I've just copy and pasted the relevant methods in - happy to tidy up.
Based on the CI output it looks like #512 also introduced an issue Rails 5.0 and 5.1 when defining abilities with nested hashes? If you reverse the changes made in #512 then the new tests here I've added all pass. Because of this, I'm proposing we only use Before I continue down this path I'm keen for feedback on if the 2 changes I'm proposing in this PR are worthwhile, and if it makes more sense to split them into separate PRs. Here's the changelog for reference: a9642b2 |
Great work! I am very happy you have found my code useful, and I cant wait to use this instead of my own gem :-) |
Hi @ghiculescu . Thanks for the time you put in this PR.
I therefore see an error in the examples you provided but which is not related to the Here are my considerations at the moment:
Can you help me to reproduce your issue? If I have missed something please point to me. I do not absolutely exclude that I might have missed something. 😄 Thanks 🙏 |
One additional note regarding your comment:
|
@coorasse here's how to replicate: https://gist.github.com/ghiculescu/a3a713134f18e351c7ba521377146014 Take the tests I've added in this PR and nothing else, and run Note that the tests don't fail if you're using sqlite. But I use postgres in production, that's how I came across the issue. |
@coorasse any more thoughts on this one? If you aren't happy with this style of fix I can go back and work around this issue in my code. Keen to get a resolution one way or another as this is blocking our rails 6 update. |
We have ended up working around this in our codebase. |
Problem
If you have a
default_scope
that sets ordering, and define a permission that checks for records via multiple tables, and use ahas_many :through
, and run Postgres... then on version 3.x,accessible_by
may crash. The attached test suite shows how; the tests that callalex.blog_post_comments
fail with:This regressed in #512
Previous query (worked fine):
New query (crashes):
After writing this up I realised there was a much simpler replication case reported here: #508 (comment)
Also I know that this is mentioned in the updating notes but in my opinion cancancan should be able to handle this for the user.
Solution
Okay so I kind of hate this PR but I haven't found a better solution. There's a few things going on here.
add_joins_to_relation
.Relation#left_joins
does not work super well in AR 5.0 and 5.1; it's failing on a bunch of the tests added in this PR. Thus I'm not using it for older Rails versions; for those I'm falling back to how joins worked before Kaspernj optimised queries with left joins #512.extract_ids_and_requery
has like a million comments explaining what it does. It means we'll be running an extra query fairly often so I'm keen for feedback on if this is actually worth doing.Basically I hate this solution but I can't find another way of getting it to work if we keep
left_joins
. And if we ditchleft_joins
, there's still things that don't work. For example, there's some tests that doPost.accessible_by(ability).select('title as mytitle')
that only work if you useleft_joins
(they were introduced after #512).