djezzzl / database_consistency

The tool to avoid various issues due to inconsistencies and inefficiencies between a database schema and application models.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

MissingAssociationClassChecker fails with `undefined method klass for nil:NilClass`

eduardoj opened this issue · comments

Recently introduced MissingAssociationClassChecker checker fails for our setup. You can see the setup in this pull request, where the check finally got disabled: openSUSE/open-build-service#14627

Content of the database_consistency_DATE file returned: ``` <===begin===> /usr/lib64/ruby/gems/3.1.0/gems/activerecord-7.0.4.3/lib/active_record/reflection.rb:814:in `source_reflection': undefined method `klass' for nil:NilClass (NoMethodError)
    through_reflection.klass._reflect_on_association(source_reflection_name)
                      ^^^^^^
    from /usr/lib64/ruby/gems/3.1.0/gems/activerecord-7.0.4.3/lib/active_record/reflection.rb:1021:in `derive_class_name'
    from /usr/lib64/ruby/gems/3.1.0/gems/activerecord-7.0.4.3/lib/active_record/reflection.rb:166:in `class_name'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/checkers/association_checkers/missing_association_class_checker.rb:30:in `report_template'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/checkers/association_checkers/missing_association_class_checker.rb:22:in `rescue in check'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/checkers/association_checkers/missing_association_class_checker.rb:18:in `check'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/checkers/base_checker.rb:25:in `report'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/checkers/base_checker.rb:34:in `report_if_enabled?'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/associations_processor.rb:25:in `block (3 levels) in check'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/associations_processor.rb:23:in `each'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/associations_processor.rb:23:in `flat_map'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/associations_processor.rb:23:in `block (2 levels) in check'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/associations_processor.rb:22:in `each'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/associations_processor.rb:22:in `flat_map'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/associations_processor.rb:22:in `block in check'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/associations_processor.rb:18:in `each'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/associations_processor.rb:18:in `flat_map'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/associations_processor.rb:18:in `check'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/base_processor.rb:30:in `reports'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/base_processor.rb:15:in `block in reports'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/base_processor.rb:14:in `each'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/base_processor.rb:14:in `flat_map'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/base_processor.rb:14:in `reports'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency.rb:104:in `run'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/bin/database_consistency:78:in `<top (required)>'
    from /usr/bin/database_consistency:25:in `load'
    from /usr/bin/database_consistency:25:in `<main>'

/usr/lib64/ruby/gems/3.1.0/gems/activerecord-7.0.4.3/lib/active_record/reflection.rb:814:in source_reflection': undefined method klass' for nil:NilClass (NoMethodError)

    through_reflection.klass._reflect_on_association(source_reflection_name)
                      ^^^^^^
    from /usr/lib64/ruby/gems/3.1.0/gems/activerecord-7.0.4.3/lib/active_record/reflection.rb:1021:in `derive_class_name'
    from /usr/lib64/ruby/gems/3.1.0/gems/activerecord-7.0.4.3/lib/active_record/reflection.rb:166:in `class_name'
    from /usr/lib64/ruby/gems/3.1.0/gems/activerecord-7.0.4.3/lib/active_record/reflection.rb:793:in `klass'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/checkers/association_checkers/missing_association_class_checker.rb:19:in `check'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/checkers/base_checker.rb:25:in `report'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/checkers/base_checker.rb:34:in `report_if_enabled?'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/associations_processor.rb:25:in `block (3 levels) in check'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/associations_processor.rb:23:in `each'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/associations_processor.rb:23:in `flat_map'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/associations_processor.rb:23:in `block (2 levels) in check'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/associations_processor.rb:22:in `each'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/associations_processor.rb:22:in `flat_map'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/associations_processor.rb:22:in `block in check'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/associations_processor.rb:18:in `each'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/associations_processor.rb:18:in `flat_map'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/associations_processor.rb:18:in `check'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/base_processor.rb:30:in `reports'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/base_processor.rb:15:in `block in reports'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/base_processor.rb:14:in `each'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/base_processor.rb:14:in `flat_map'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency/processors/base_processor.rb:14:in `reports'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/lib/database_consistency.rb:104:in `run'
    from /usr/lib64/ruby/gems/3.1.0/gems/database_consistency-1.7.13/bin/database_consistency:78:in `<top (required)>'
    from /usr/bin/database_consistency:25:in `load'
    from /usr/bin/database_consistency:25:in `<main>'

<===end===>

</details>

Hi @eduardoj,

Thank you for reporting this!

Looking at your stack trace, the problem is in your application rather than the checker. I mean checker exposed the issue out load (not in silent mode).

One of your associations is "broken" because it doesn't have through_reflection when the ActiveRecord code expects it to be there. It could be a bug with ActiveRecord itself too.

Please add a simple put mode, the association before checkers/association_checkers/missing_association_class_checker.rb:19 to track down what causes this to fail.

through_reflection.klass._reflect_on_association(source_reflection_name)
                      ^^^^^^
    from /usr/lib64/ruby/gems/3.1.0/gems/activerecord-7.0.4.3/lib/active_record/reflection.rb:1021:in `derive_class_name'
    from /usr/lib64/ruby/gems/3.1.0/gems/activerecord-7.0.4.3/lib/active_record/reflection.rb:166:in `class_name'

P.S. You don't need to turn off the check entirely; you can disable only those that fail.

Hi @djezzzl!

That's right. You helped me to find a problem in my application.

After fixing the problem, I had no issues with the checker. I will close this issue.

Sorry if opening this issue, not related to this project created some noise. Thanks for your fast and detailed response!

That's right. You helped me to find openSUSE/open-build-service#14645 in my application.

Glad that it helped!

Sorry if opening this issue, not related to this project created some noise. Thanks for your fast and detailed response!

No worries at all! I'm glad I could help. And, BTW, you helped me to understand that the error output could be improved with more context, such as failing checker information.

And also, you helped with an idea to write a checker to cover your case (when a through association is broken).

Have a great weekend!