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

Rails/UniqueValidationWithoutIndex errors on namespaced models #348

Closed
Timmitry opened this issue Sep 7, 2020 · 16 comments
Closed

Rails/UniqueValidationWithoutIndex errors on namespaced models #348

Timmitry opened this issue Sep 7, 2020 · 16 comments
Labels
bug Something isn't working

Comments

@Timmitry
Copy link

Timmitry commented Sep 7, 2020

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 ' /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 ' /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 ' /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 ' /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 `' /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 `' /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 ' /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 `' /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 `'

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 👍

@Bialogs
Copy link

Bialogs commented Sep 7, 2020

I am also seeing this problem on Rubocop v0.90.0. Not sure what @Timmitry means by namespaced model, but the error happens on a model using single table inheritance in my project.

Here is the portion of the schema since I know that maintainers have requested the schema in the past for this issue.

  create_table "groups", id: :serial, force: :cascade do |t|
    t.string "name", limit: 255
    t.string "poc_name", limit: 255
    t.string "poc_phone", limit: 255
    t.string "poc_email", limit: 255
    t.datetime "open_at"
    t.datetime "close_at"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "code", limit: 255
    t.text "welcome_message"
    t.text "questions"
    t.text "delivery_message"
    t.string "salesperson_name", limit: 255
    t.integer "shipping_cents", default: 0, null: false
    t.string "currency", limit: 255
    t.string "email_interval", limit: 255
    t.integer "salesperson_id"
    t.integer "organization_id"
    t.boolean "shipping_optional", default: false
    t.date "delivery_date"
    t.string "type", default: "TemporaryGroup"
    t.string "image"
    t.integer "days_until_delivery"
    t.float "tax", default: 0.0, null: false
  end

@Timmitry
Copy link
Author

Timmitry commented Sep 8, 2020

@Bialogs With namespaced I meant that the model is in a module, as can be seen by the MeasuringPointConcept::-prefix.

And if the schema might help, here it is:

  create_table "measuring_point_concept_sensor_imports", force: :cascade do |t|
    t.bigint "node_import_id"
    t.string "name"
    t.integer "channel_number"
    t.string "sensor_name"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["node_import_id"], name: "index_measuring_point_concept_sensor_imports"
  end

@Tietew
Copy link
Contributor

Tietew commented Sep 8, 2020

#349 fixes an error when the related table is not found.

@Jay-Schneider
Copy link

I can confirm this behaviour. With my code it happens exactly after updating rubocop-rails from 2.7.1. (no error) to 2.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.

@Tietew
Copy link
Contributor

Tietew commented Sep 8, 2020

@Jay-Schneider Yes, you're right. But my PR just fixes the error -- in my case, the table really doesn't exist. This issue seems to be false negative problem.

@rbclark
Copy link

rbclark commented Sep 8, 2020

Seeing this problem as well, in my case it is an extremely simple model:

class Achievement < FeedItem
  validates :text, presence: true, uniqueness: true
end

However, since it is using STI, the associated database table is called feed_items, not achievements.

  create_table "feed_items", id: :serial, force: :cascade do |t|
    t.integer "user_id"
    t.integer "team_id"
    t.integer "division_id"
    t.string "text"
    t.integer "challenge_id"
    t.integer "point_value"
    t.integer "flag_id"
    t.string "type"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

@coding-red-panda
Copy link

This problem also occurs with Modules using ActiveRecord:

# rubocop:disable Rails/UniqueValidationWithoutIndex
module Sluggable
  extend ActiveSupport::Concern

  included do
    validates :slug, uniqueness: true, format: { with: /\A[\w-]*\z/ }, length: { maximum: 255 }

    # Generates not-yet-taken slug by appending numbers if necessary.
    def self.generate_unique_slug(slug)
      new_slug = slug.parameterize

      # XXX: LENGTH + 1 because PostgreSQL indexes characters in strings from 1
      max_duplicate = where("slug SIMILAR TO ?", "#{new_slug}-[0123456789]+")
                      .pick(
                        Arel.sql(format("MAX(CAST(SUBSTRING(slug FROM LENGTH(%<slug>s) + 1) AS numeric))",
                                        slug: ActiveRecord::Base.connection.quote("#{new_slug}-")))
                      )&.to_i
      # This loop should not be needed anymore, but let's keep it for the peace of mind.
      i = (max_duplicate || 0) + 1
      while find_by_slug(new_slug)
        new_slug = "#{slug} #{i}".parameterize
        i += 1
      end
      new_slug
    end

    def generate_slug
      if slug.blank? && name.present?
        self.slug = self.class.generate_unique_slug(name)
      end
    end
  end
end
# rubocop:enable Rails/UniqueValidationWithoutIndex

Error:

An error occurred while Rails/UniqueValidationWithoutIndex cop was inspecting /Users/olivar/RubymineProjects/customink-for-business/app/models/concerns/sluggable.rb:6:4.
undefined method `each_node' for nil:NilClass
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-rails-2.8.0/lib/rubocop/cop/mixin/active_record_helper.rb:14:in `find_set_table_name'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-rails-2.8.0/lib/rubocop/cop/mixin/active_record_helper.rb:35:in `each'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-rails-2.8.0/lib/rubocop/cop/mixin/active_record_helper.rb:35:in `to_a'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-rails-2.8.0/lib/rubocop/cop/mixin/active_record_helper.rb:35:in `table_name'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-rails-2.8.0/lib/rubocop/cop/rails/unique_validation_without_index.rb:49:in `find_schema_information'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-rails-2.8.0/lib/rubocop/cop/rails/unique_validation_without_index.rb:38:in `on_send'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/cop/commissioner.rb:99:in `block (2 levels) in trigger_responding_cops'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/cop/commissioner.rb:152:in `with_cop_error_handling'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/cop/commissioner.rb:98:in `block in trigger_responding_cops'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/cop/commissioner.rb:97:in `each'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/cop/commissioner.rb:97:in `trigger_responding_cops'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/cop/commissioner.rb:70:in `on_send'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/traversal.rb:59:in `block in on_begin'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/traversal.rb:59:in `each'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/traversal.rb:59:in `on_begin'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/cop/commissioner.rb:72:in `on_begin'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/traversal.rb:173:in `on_block'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/cop/commissioner.rb:72:in `on_block'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/traversal.rb:59:in `block in on_begin'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/traversal.rb:59:in `each'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/traversal.rb:59:in `on_begin'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/cop/commissioner.rb:72:in `on_begin'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/traversal.rb:159:in `on_while'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/cop/commissioner.rb:72:in `on_module'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-ast-0.3.0/lib/rubocop/ast/traversal.rb:14:in `walk'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/cop/commissioner.rb:85:in `investigate'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/cop/team.rb:152:in `investigate_partial'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/cop/team.rb:83:in `investigate'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/runner.rb:296:in `inspect_file'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/runner.rb:246:in `block in do_inspection_loop'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/runner.rb:278:in `block in iterate_until_no_changes'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/runner.rb:271:in `loop'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/runner.rb:271:in `iterate_until_no_changes'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/runner.rb:242:in `do_inspection_loop'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/runner.rb:122:in `block in file_offenses'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/runner.rb:147:in `file_offense_cache'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/runner.rb:121:in `file_offenses'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/runner.rb:112:in `process_file'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/runner.rb:91:in `block in each_inspected_file'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/runner.rb:90:in `each'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/runner.rb:90:in `reduce'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/runner.rb:90:in `each_inspected_file'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/runner.rb:79:in `inspect_files'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/runner.rb:40:in `run'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/cli/command/execute_runner.rb:22:in `execute_runner'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/cli/command/execute_runner.rb:14:in `run'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/cli/command.rb:11:in `run'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/cli/environment.rb:18:in `run'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/cli.rb:65:in `run_command'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/cli.rb:72:in `execute_runners'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/lib/rubocop/cli.rb:41:in `run'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/exe/rubocop:13:in `block in <top (required)>'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/2.7.0/benchmark.rb:308:in `realtime'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/rubocop-0.90.0/exe/rubocop:12:in `<top (required)>'
/Users/olivar/.rbenv/versions/2.7.1/bin/rubocop:23:in `load'
/Users/olivar/.rbenv/versions/2.7.1/bin/rubocop:23:in `<top (required)>'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/lib/bundler/cli/exec.rb:63:in `load'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/lib/bundler/cli/exec.rb:63:in `kernel_load'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/lib/bundler/cli/exec.rb:28:in `run'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/lib/bundler/cli.rb:476:in `exec'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/lib/bundler/vendor/thor/lib/thor.rb:399:in `dispatch'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/lib/bundler/cli.rb:30:in `dispatch'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/lib/bundler/vendor/thor/lib/thor/base.rb:476:in `start'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/lib/bundler/cli.rb:24:in `start'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/exe/bundle:46:in `block in <top (required)>'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/lib/bundler/friendly_errors.rb:123:in `with_friendly_errors'
/Users/olivar/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/exe/bundle:34:in `<top (required)>'
/Users/olivar/.rbenv/versions/2.7.1/bin/bundle:23:in `load'
/Users/olivar/.rbenv/versions/2.7.1/bin/bundle:23:in `<main>'

As you can see from the code-snippet, trying to disable the Cop has no effect

@andyw8
Copy link
Contributor

andyw8 commented Sep 9, 2020

@coding-bunny That's strange... if you move the RuboCop directives to only around the validates lines, does it still occur? i.e.

# rubocop:disable Rails/UniqueValidationWithoutIndex
validates :slug, uniqueness: true, format: { with: /\A[\w-]*\z/ }, length: { maximum: 255 }
# rubocop:enable Rails/UniqueValidationWithoutIndex

@Tietew
Copy link
Contributor

Tietew commented Sep 10, 2020

@coding-bunny @andyw8 #349 has been merged. It also fixed an error when validates is not in class.

@coding-red-panda
Copy link

@coding-bunny That's strange... if you move the RuboCop directives to only around the validates lines, does it still occur? i.e.

# rubocop:disable Rails/UniqueValidationWithoutIndex
validates :slug, uniqueness: true, format: { with: /\A[\w-]*\z/ }, length: { maximum: 255 }
# rubocop:enable Rails/UniqueValidationWithoutIndex

Yes, it doesn't matter at all where those comments were placed.
Actually RuboCop threw me a warning saying that they are "useless" and should be removed even.

@coding-bunny @andyw8 #349 has been merged. It also fixed an error when validates is not in class.

Thank you!
Will wait on the next release then

@Bialogs
Copy link

Bialogs commented Sep 10, 2020

@coding-bunny I had success disabling the check at the .rubocop.yml level.

@coding-red-panda
Copy link

Yeah but I don't want the check disabled or the file ignored.

@MrJoy
Copy link

MrJoy commented Sep 13, 2020

I have a situation in which this is coming up in which I have the proper index, but I'm using a scoped unique constraint, AND the table is in a secondary database.

Also, attempting to disable the cop inline is not helping prevent the error. E.G.

class SomeDimension < OLAPRecord
  # rubocop:disable Rails/UniqueValidationWithoutIndex
  validates :some_field, presence: true, uniqueness: { scope: :some_other_field, case_sensitive: false }
  # rubocop:enable Rails/UniqueValidationWithoutIndex
end

That still causes an error.

@koic
Copy link
Member

koic commented Sep 15, 2020

This issue has been resolved by #349 and RuboCop Rails 2.8.1 has been released. Can you upgrade to the latest RuboCop Rails?

@Bialogs
Copy link

Bialogs commented Sep 15, 2020

@koic Do you have any thoughts on @Jay-Schneider critique of that PR in his message above?

@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 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?

@koic
Copy link
Member

koic commented Aug 20, 2021

I think the undefined method 'with_column?' for nil:NilClass error 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 like Module#ancestors. Thank you.

@koic koic closed this as completed Aug 20, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

9 participants