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

Add new Rails/ArelStar cop #344

Merged
merged 1 commit into from
Oct 10, 2020
Merged

Add new Rails/ArelStar cop #344

merged 1 commit into from
Oct 10, 2020

Conversation

flanger001
Copy link
Contributor

This is a new cop that checks for usage of arel_table["*"] and MyModel["*"] calls. arel_table quotes anything a user enters in the brackets and this can lead to some unexpected consequences:

class MyModel < ApplicationRecord
  scope :my_arel_scope, -> {
    select(arel_table["*"])
  }
end

puts MyModel.my_arel_scope.to_sql

# (Assuming MySQL)
#=> SELECT `my_models`.`*` FROM `my_models` 

This is correct-looking but actually incorrect SQL because a quoted asterisk is treated as a literal column name by MySQL and Postgres. I have not tried this in SQLite but I imagine it does the same thing.

Thanks for taking a look!


Before submitting the PR make sure the following are checked:

  • Wrote good commit messages.
  • Commit message starts with [Fix #issue-number] (if the related issue exists).
  • Feature branch is up-to-date with master (if not - rebase it).
  • Squashed related commits together.
  • Added tests.
  • Added an entry to the Changelog if the new code introduces user-observable changes. See changelog entry format.
  • If this is a new cop, consider making a corresponding update to the Rails Style Guide.
  • The PR relates to only one subject with a clear title
    and description in grammatically correct, complete sentences.
  • Run bundle exec rake default. It executes all tests and RuboCop for itself, and generates the documentation.

@flanger001 flanger001 force-pushed the dms/arel-star branch 7 times, most recently from d1ec291 to f2ab74e Compare September 4, 2020 17:58
@andyw8
Copy link
Contributor

andyw8 commented Sep 4, 2020

Might this be considered as a bug in Arel?

@flanger001
Copy link
Contributor Author

@andyw8 I think you could make the argument either way honestly. Arel should probably not quote asterisks, but the core team will also likely say that Arel should not be used publicly. What do you think?

@dvandersluis
Copy link
Member

dvandersluis commented Sep 4, 2020

Since * is a valid column identifier on both MySQL and Postgres (regardless of whether it should be), it's probably not a bug, Arel or not. However, behaviour did change in MySQL 8.0.21, and anyone upgrading to that will suddenly have their queries break (we experienced this at work).

@flanger001
Copy link
Contributor Author

Actually, upon further consideration, I am not so sure this could be considered a bug. Having an asterisk as a column name is an extraordinarily bad idea, but there is nothing technically incorrect about it. These are both valid DDL for PostgreSQL and MySQL respectively:

CREATE TABLE foos ("*" varchar(255));
CREATE TABLE foos (`*` varchar(255));

So the arel_table["*"] usage would be correct in these cases, however abhorrent they might be.

@flanger001
Copy link
Contributor Author

However, behaviour did change in MySQL 8.0.21, and anyone upgrading to that will suddenly have their queries break (we experienced this at work).

This is what happened to me as well, and indeed it was the impetus for this cop.

@andyw8
Copy link
Contributor

andyw8 commented Sep 4, 2020

I think there's also a policy decision to be made here. Since Arel is still considered a private internal API (recent discussion) should it be in scope for rubocop-rails?

@dvandersluis
Copy link
Member

I was involved with that discussion and despite what the rails team has said, there are quite a few developers using Arel. No need to relitigate whether or not Arel should be public here, but since developers are using it and this is a real thing that can be encountered, I think the cop makes sense here.

@flanger001
Copy link
Contributor Author

Hey, I'm all over that discussion!

Again, I think you could make the case either way. I personally think it should be in scope. arel_table in particular is used very frequently, and it not being a public API does not have any effect on the very real usage of it in the wild.

@flanger001
Copy link
Contributor Author

Also it appears @dvandersluis and I are hitting the same exact beats here, but I would imagine this is the majority sentiment.

@flanger001
Copy link
Contributor Author

@andyw8 Any further thoughts on this?

@andyw8
Copy link
Contributor

andyw8 commented Sep 9, 2020

I'm still on the fence, but if another maintainer gives it a 👍 then let's go ahead.

@flanger001
Copy link
Contributor Author

Cool, thank you.

@flanger001 flanger001 force-pushed the dms/arel-star branch 2 times, most recently from 6a3cf24 to 3c81b6a Compare September 9, 2020 20:00
@flanger001
Copy link
Contributor Author

I'm happy to close this if there's no interest but any chance I can get another set of eyes on this?

CHANGELOG.md Outdated
@@ -7,6 +7,8 @@
* [#345](https://github.com/rubocop-hq/rubocop-rails/issues/345): Fix error of `Rails/AfterCommitOverride` on `after_commit` with a lambda. ([@pocke][])
* [#349](https://github.com/rubocop-hq/rubocop-rails/pull/349): Fix errors of `Rails/UniqueValidationWithoutIndex`. ([@Tietew][])

* [#344](https://github.com/rubocop-hq/rubocop-rails/pull/344): Add new `Rails/ArelStar` cop which checks for quoted literal asterisks in `arel_table` calls. ([@flanger001][])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you rebase with the latest master branch and move this entry to New features section?

Rails/ArelStar:
Description: 'Enforces `Arel.star` instead of `"*"` for expanded columns.'
Enabled: true
Safe: false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you write a reason to description of the cop why it is unsafe?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. I will add this description in here:

This cop is unsafe because it checks for ["*"].

hsh = { "*" => true }
hsh["*"] # This would get corrected to `hsh[Arel.star]`

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get it, thank you for the address!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on @eugeneius's review here #344 (review) I removed this description. I think it is still a good idea to call this an unsafe cop, but I'm open to feedback here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the update. If my understanding is correct, there seems to be concern about incompatible behavior rather than false positives. If so, SafeAutoCorrect: false would be more eligible than Safe: false.

-Safe: false
+SafeAutoCorrect: false

https://docs.rubocop.org/rubocop/0.92/usage/auto_correct.html#safe-auto-correct

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@koic sounds good to me, and thanks for the clarification. I've pushed this up!

Description: 'Enforces `Arel.star` instead of `"*"` for expanded columns.'
Enabled: true
Safe: false
SafeAutoCorrect: false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this due to when Safe: false then SafeAutocorrect is also false.

Enabled: true
Safe: false
SafeAutoCorrect: false
AutoCorrect: false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any reason to set this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I set this to not autocorrect by default because it is unsafe.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, I think this setting is unnecessary due to Safe: false is not auto-corrected by default rubocop -a safe option. (In that case, users will explicitly use rubocop -A unsefe option.)

RESTRICT_ON_SEND = %i[[]].freeze

def_node_matcher :star_bracket?, <<~PATTERN
(send {const {_ :arel_table}} :[] $(str "*"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{_ :arel_table} means "anything or :arel_table", which will always match.

Similarly, the entire {const {_ :arel_table}} expression matches any node, and is equivalent to _.

I guess perhaps you meant to write:

Suggested change
(send {const {_ :arel_table}} :[] $(str "*"))
(send {const (send _ :arel_table)} :[] $(str "*"))

...which would resolve the false positive case mentioned in #344 (comment).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eugeneius This is a good change, thank you!

@flanger001 flanger001 force-pushed the dms/arel-star branch 2 times, most recently from 8d65eff to b549626 Compare October 7, 2020 19:15
@koic koic merged commit d4958b9 into rubocop:master Oct 10, 2020
@koic
Copy link
Member

koic commented Oct 10, 2020

Thank you!

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.

5 participants