rubocop-rails: Rails/UniqueValidationWithoutIndex errors on namespaced models
Expected behavior
Rubocop-rails should not output any errors
Actual behavior
Running rubocop outputs
An error occurred while Rails/UniqueValidationWithoutIndex cop was inspecting /Users/tim.landwerth/*/app/models/measuring_point_concept/sensor_import.rb:4:2.
undefined method `with_column?' for nil:NilClass
An error occurred while Rails/UniqueValidationWithoutIndex cop was inspecting /Users/tim.landwerth/*/app/models/measuring_point_concept/sensor_import.rb:4:2.
undefined method `with_column?' for nil:NilClass
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-rails-2.8.0/lib/rubocop/cop/mixin/active_record_helper.rb:55:in `resolve_relation_into_column'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-rails-2.8.0/lib/rubocop/cop/rails/unique_validation_without_index.rb:84:in `block in column_names'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-rails-2.8.0/lib/rubocop/cop/rails/unique_validation_without_index.rb:82:in `map!'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-rails-2.8.0/lib/rubocop/cop/rails/unique_validation_without_index.rb:82:in `column_names'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-rails-2.8.0/lib/rubocop/cop/rails/unique_validation_without_index.rb:50:in `find_schema_information'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-rails-2.8.0/lib/rubocop/cop/rails/unique_validation_without_index.rb:38:in `on_send'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/cop/commissioner.rb:91:in `block (2 levels) in trigger_responding_cops'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/cop/commissioner.rb:113:in `with_cop_error_handling'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/cop/commissioner.rb:90:in `block in trigger_responding_cops'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/cop/commissioner.rb:89:in `each'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/cop/commissioner.rb:89:in `trigger_responding_cops'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/cop/commissioner.rb:61:in `block (2 levels) in <class:Commissioner>'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/traversal.rb:59:in `block in on_begin'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/traversal.rb:59:in `each'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/traversal.rb:59:in `on_begin'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/cop/commissioner.rb:62:in `block (2 levels) in <class:Commissioner>'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/traversal.rb:101:in `on_class'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/cop/commissioner.rb:62:in `block (2 levels) in <class:Commissioner>'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/traversal.rb:14:in `walk'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/cop/commissioner.rb:74:in `investigate'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/cop/team.rb:151:in `investigate_partial'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/cop/team.rb:83:in `investigate'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:295:in `inspect_file'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:245:in `block in do_inspection_loop'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:277:in `block in iterate_until_no_changes'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:270:in `loop'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:270:in `iterate_until_no_changes'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:241:in `do_inspection_loop'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:121:in `block in file_offenses'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:146:in `file_offense_cache'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:120:in `file_offenses'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:111:in `process_file'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:90:in `block in each_inspected_file'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:89:in `each'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:89:in `reduce'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:89:in `each_inspected_file'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:78:in `inspect_files'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/runner.rb:39:in `run'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/cli/command/execute_runner.rb:21:in `execute_runner'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/cli/command/execute_runner.rb:13:in `run'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/cli/command.rb:10:in `run'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/cli/environment.rb:17:in `run'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/cli.rb:65:in `run_command'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/cli.rb:72:in `execute_runners'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/lib/rubocop/cli.rb:41:in `run'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/exe/rubocop:13:in `block in <top (required)>'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/2.6.0/benchmark.rb:308:in `realtime'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-0.88.0/exe/rubocop:12:in `<top (required)>'
/Users/tim.landwerth/.rbenv/versions/2.6.6/bin/rubocop:23:in `load'
/Users/tim.landwerth/.rbenv/versions/2.6.6/bin/rubocop:23:in `<top (required)>'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/cli/exec.rb:63:in `load'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/cli/exec.rb:63:in `kernel_load'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/cli/exec.rb:28:in `run'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/cli.rb:476:in `exec'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/vendor/thor/lib/thor.rb:399:in `dispatch'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/cli.rb:30:in `dispatch'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/vendor/thor/lib/thor/base.rb:476:in `start'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/cli.rb:24:in `start'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/exe/bundle:46:in `block in <top (required)>'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/lib/bundler/friendly_errors.rb:123:in `with_friendly_errors'
/Users/tim.landwerth/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/exe/bundle:34:in `<top (required)>'
/Users/tim.landwerth/.rbenv/versions/2.6.6/bin/bundle:23:in `load'
/Users/tim.landwerth/.rbenv/versions/2.6.6/bin/bundle:23:in `<main>'
Steps to reproduce the problem
Sorry, I do not have a reproducible example yet - but I would think that namespaced models cause the problem, since it errors on a few files, which all have a namespace - e.g.:
class MeasuringPointConcept::SensorImport < ApplicationRecord
belongs_to :node_import, class_name: "MeasuringPointConcept::NodeImport", optional: true
validates :channel_number, presence: true, numericality: true, uniqueness: { scope: :node_import_id }
validates :sensor_name, presence: true
...
end
RuboCop version
0.88.0 (using Parser 2.7.1.4, rubocop-ast 0.3.0, running on ruby 2.6.6 x86_64-darwin18)
Thanks and keep up the great work 👍
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 14
- Comments: 16 (6 by maintainers)
Yeah but I don’t want the check disabled or the file ignored.
@koic Do you have any thoughts on @Jay-Schneider critique of that PR in his message above?
I tend to agree with @Jay-Schneider. If the class that the validation is crashing on is actually a subclass of a model with a table in the database, shouldn’t the real fix be to walk the inheritance up to the ActiveRecord Base class and check for a matching table?
I can confirm this behaviour. With my code it happens exactly after updating rubocop-rails from
2.7.1.(no error) to2.8.0(error mentioned above,undefined method 'with_column?' for nil:NilClass). It did not update any other gems or dependencies at the same time, so it seems to be related exactly to this minor update. For me, it also seems to have to do with nested classes (models defined inside a module) and probably some mistake when resolving table names from that nested class name?@Tietew: I can confirm your fix removes the error. But I am not sure if this implements the correct behaviour. See, the table does exist in our cases and is also declared in the schema.rb. Simply not running the cop against the concerned model/table seems like a hack. I believe, if I would add a validation without the unique index in such a nested class it would not be detected as an offense. If I have the time I will take a look into it myself and maybe comment your PR.
I think the
undefined method 'with_column?' for nil:NilClasserror that is the subject of the issue has been resolved. Please open another issue or a PR to improve the message. This is a technical note. Since RuboCop is a static analysis tool, it cannot use run-time analysis likeModule#ancestors. Thank you.This issue has been resolved by https://github.com/rubocop-hq/rubocop-rails/pull/349 and RuboCop Rails 2.8.1 has been released. Can you upgrade to the latest RuboCop Rails?