Giter Site home page Giter Site logo

djezzzl / database_consistency Goto Github PK

View Code? Open in Web Editor NEW
985.0 9.0 42.0 611 KB

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

License: MIT License

Ruby 92.63% JavaScript 1.84% CSS 0.62% HTML 4.90%
ruby-on-rails activerecord tool database consistency optimization performance rails ruby

database_consistency's Introduction

DatabaseConsistency

The main goal of the project is to help you avoid various issues due to inconsistencies and inefficiencies between a database schema and application models.

If the project helps you or your organization, I would be very grateful if you contribute or donate.
Your support is an incredible motivation and the biggest reward for my hard work.

For detailed information, please read the wiki.

Currently, the tool can:

Besides that, the tool provides:

We support the following databases: SQLite3, PostgreSQL and MySQL.
We support ActiveRecord only at the moment. Please upvote the request for other frameworks if you're interested.

Follow me and stay tuned for the updates:

Usage

Add this line to your application's Gemfile:

gem 'database_consistency', group: :development, require: false

And then execute:

$ bundle install

Example

$ bundle exec database_consistency
NullConstraintChecker fail User code column is required in the database but does not have a validator disallowing nil values
NullConstraintChecker fail User company_id column is required in the database but do not have presence validator for association (company)
LengthConstraintChecker fail Company note column has limit in the database but do not have length validator
MissingUniqueIndexChecker fail User name+email model should have proper unique index in the database
ForeignKeyChecker fail User company should have foreign key in the database
ForeignKeyTypeChecker fail User company associated model key (id) with type (integer) mismatches key (company_id) with type (integer(8))
MissingIndexChecker fail Company user associated model should have proper index in the database
ForeignKeyTypeChecker fail Company user associated model key (company_id) with type (integer(8)) mismatches key (id) with type (integer)
MissingIndexChecker fail Country users associated model should have proper index in the database
ColumnPresenceChecker fail User phone column should be required in the database
ColumnPresenceChecker fail User name column is required but there is possible null value insert
UniqueIndexChecker fail User index_users_on_name_and_slug index is unique in the database but do not have uniqueness validator
RedundantUniqueIndexChecker fail User index_users_on_name_and_slug index uniqueness is redundant as (index_users_on_slug) covers it
RedundantIndexChecker fail User index_users_on_phone index is redundant as (index_users_on_phone_and_slug) covers it
ColumnPresenceChecker fail User tmp column (tmp) is missing in table (users) but used for presence validation
ForeignKeyTypeChecker fail User something association (something) of class (User) relies on field (something_id) of table (users) but it is missing
ThreeStateBooleanChecker fail Company active boolean column should have NOT NULL constraint
MissingAssociationClassChecker fail Company anything refers to undefined model "Anything"
MissingTableChecker fail LegacyModel should have a table in the database
ImplicitOrderingChecker fail Secondary::User id implicit_order_column is recommended when using uuid column type for primary key

Funding

Open Collective Backers

You're an individual who wants to support the project with a monthly donation. Your logo will be available on the Github page. [Become a backer]

Open Collective Sponsors

You're an organization that wants to support the project with a monthly donation. Your logo will be available on the Github page. [Become a sponsor]

Contributing

Bug reports and pull requests are welcome on GitHub. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

Contributors

Code of Conduct

Everyone interacting in the DatabaseConsistency project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

Changelog

DatabaseConsistency's changelog is available here.

Copyright

Copyright (c) Evgeniy Demin. See LICENSE.txt for further details.

database_consistency's People

Contributors

andriusch avatar asavageiv avatar barthez avatar berardpi avatar bobmaerten avatar chaadow avatar chubchenko avatar danidoni avatar developie0610 avatar djezzzl avatar djfpaagman avatar frodsan avatar goulvench avatar ibublik avatar jlestavel avatar lyziooh avatar ojab avatar palkan avatar pirj avatar pyromaniac avatar soloveytani avatar tdeo avatar toydestroyer avatar uxxman avatar vfonic avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

database_consistency's Issues

citext false positive

Hey @djezzzl ! 👋

I have the following in db/schema.rb:

  enable_extension "citext"

  create_table "groups", force: :cascade do |t|
    t.citext "name", null: false
    t.index ["name"], name: "index_groups_on_name", unique: true

Model:

validates :name, uniqueness: { case_sensitive: false }

database_consistency complains:

MissingUniqueIndexChecker fail Group lower(name) model should have proper unique index in the database

psql mydb:

# \d groups
                                              Table "public.groups"
       Column       |              Type              | Collation | Nullable |                     Default
--------------------+--------------------------------+-----------+----------+-------------------------------------------------
 name               | citext                         |           | not null |
...
Indexes:
    "index_groups_on_name" UNIQUE, btree (name)

PostgreSQL citext extension docs: https://www.postgresql.org/docs/current/citext.html

I've debugged it, and:

sorted_uniqueness_validator_columns # => ["lower(name)"]
Helper.extract_index_columns(index.columns).sort # => ["name"]

💥

Does it make sense to remove/ignore lower( from the index column if this column's type is citext?

database_consistency version 1.1.2

Unhandled exception in ForeignKeyTypeChecker

I encountered a couple of errors when running the latest update of database_consistency

ruby 2.6.6p146
rails 5.2.4.4
database_consistency 0.8.9
postgresql 12.4

The errors pertain to associations from a table-backed model to two view-backed models
Association (import_member) of class (ImportRow) relies on field (id) of table (import_members) but it is missing. (DatabaseConsistency::Errors::MissingField)

Since the parent model is based on a view it is not possible to set a FK relationship. Although there may be some another constraint / consistency that I'm still lacking. Regardless, I'm not sure if this is a case that should be supported or handled, but in the spirit of the error message given I thought I would open an issue just to make sure.

Output database_consistency_2020_11_18_17_20_21

<===begin===>
�[1mTraceback�[m (most recent call last):
	37: from /Users/bencallaway/.gem/ruby/2.6.6/bin/bundle:23:in `<main>'
	36: from /Users/bencallaway/.gem/ruby/2.6.6/bin/bundle:23:in `load'
	35: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/exe/bundle:34:in `<top (required)>'
	34: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/friendly_errors.rb:123:in `with_friendly_errors'
	33: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/exe/bundle:46:in `block in <top (required)>'
	32: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/cli.rb:24:in `start'
	31: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/vendor/thor/lib/thor/base.rb:476:in `start'
	30: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/cli.rb:30:in `dispatch'
	29: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/vendor/thor/lib/thor.rb:399:in `dispatch'
	28: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
	27: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
	26: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/cli.rb:476:in `exec'
	25: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/cli/exec.rb:28:in `run'
	24: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/cli/exec.rb:63:in `kernel_load'
	23: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/cli/exec.rb:63:in `load'
	22: from /Users/bencallaway/.gem/ruby/2.6.6/bin/database_consistency:23:in `<top (required)>'
	21: from /Users/bencallaway/.gem/ruby/2.6.6/bin/database_consistency:23:in `load'
	20: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/bin/database_consistency:44:in `<top (required)>'
	19: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency.rb:47:in `run'
	18: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/base_processor.rb:12:in `reports'
	17: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/base_processor.rb:12:in `flat_map'
	16: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/base_processor.rb:12:in `each'
	15: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/base_processor.rb:13:in `block in reports'
	14: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/base_processor.rb:28:in `reports'
	13: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/associations_processor.rb:15:in `check'
	12: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/associations_processor.rb:15:in `flat_map'
	11: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/associations_processor.rb:15:in `each'
	10: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/associations_processor.rb:18:in `block in check'
	 9: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/associations_processor.rb:18:in `flat_map'
	 8: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/associations_processor.rb:18:in `each'
	 7: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/associations_processor.rb:19:in `block (2 levels) in check'
	 6: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/associations_processor.rb:19:in `map'
	 5: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/associations_processor.rb:21:in `block (3 levels) in check'
	 4: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/checkers/base_checker.rb:34:in `report_if_enabled?'
	 3: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/checkers/base_checker.rb:25:in `report'
	 2: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:40:in `check'
	 1: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:85:in `associated_column'
/Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:99:in `column': �[1mAssociation (import_member) of class (ImportRow) relies on field (id) of table (import_members) but it is missing. (�[1;4mDatabaseConsistency::Errors::MissingField�[m�[1m)�[m
<===end===>
<===begin===>
�[1mTraceback�[m (most recent call last):
	37: from /Users/bencallaway/.gem/ruby/2.6.6/bin/bundle:23:in `<main>'
	36: from /Users/bencallaway/.gem/ruby/2.6.6/bin/bundle:23:in `load'
	35: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/exe/bundle:34:in `<top (required)>'
	34: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/friendly_errors.rb:123:in `with_friendly_errors'
	33: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/gems/2.6.0/gems/bundler-2.1.4/exe/bundle:46:in `block in <top (required)>'
	32: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/cli.rb:24:in `start'
	31: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/vendor/thor/lib/thor/base.rb:476:in `start'
	30: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/cli.rb:30:in `dispatch'
	29: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/vendor/thor/lib/thor.rb:399:in `dispatch'
	28: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
	27: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
	26: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/cli.rb:476:in `exec'
	25: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/cli/exec.rb:28:in `run'
	24: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/cli/exec.rb:63:in `kernel_load'
	23: from /Users/bencallaway/.rubies/ruby-2.6.6/lib/ruby/site_ruby/2.6.0/bundler/cli/exec.rb:63:in `load'
	22: from /Users/bencallaway/.gem/ruby/2.6.6/bin/database_consistency:23:in `<top (required)>'
	21: from /Users/bencallaway/.gem/ruby/2.6.6/bin/database_consistency:23:in `load'
	20: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/bin/database_consistency:44:in `<top (required)>'
	19: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency.rb:47:in `run'
	18: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/base_processor.rb:12:in `reports'
	17: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/base_processor.rb:12:in `flat_map'
	16: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/base_processor.rb:12:in `each'
	15: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/base_processor.rb:13:in `block in reports'
	14: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/base_processor.rb:28:in `reports'
	13: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/associations_processor.rb:15:in `check'
	12: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/associations_processor.rb:15:in `flat_map'
	11: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/associations_processor.rb:15:in `each'
	10: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/associations_processor.rb:18:in `block in check'
	 9: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/associations_processor.rb:18:in `flat_map'
	 8: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/associations_processor.rb:18:in `each'
	 7: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/associations_processor.rb:19:in `block (2 levels) in check'
	 6: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/associations_processor.rb:19:in `map'
	 5: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/processors/associations_processor.rb:21:in `block (3 levels) in check'
	 4: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/checkers/base_checker.rb:34:in `report_if_enabled?'
	 3: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/checkers/base_checker.rb:25:in `report'
	 2: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:40:in `check'
	 1: from /Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:85:in `associated_column'
/Users/bencallaway/.gem/ruby/2.6.6/gems/database_consistency-0.8.9/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:99:in `column': �[1mAssociation (import_table) of class (ImportRow) relies on field (id) of table (import_tables) but it is missing. (�[1;4mDatabaseConsistency::Errors::MissingField�[m�[1m)�[m
<===end===>

Crash on inexistant column validation

rails new tst
cd tst
rails g model book
rails db:create db:migrate

and model

class XxxValidator < ActiveModel::Validator
  def validate(_record)
  end
end

class Book < ApplicationRecord
  validates :title, presence: true, xxx: true
end

leads to crash and report a bug request:

…/database_consistency-1.1.5/lib/database_consistency/checkers/validators_fraction_checkers/column_presence_checker.rb:47:in `column': Missing column in books for title (DatabaseConsistency::Errors::MissingField)
	from …/database_consistency-1.1.5/lib/database_consistency/checkers/validators_fraction_checkers/column_presence_checker.rb:32:in `check'
	from …/database_consistency-1.1.5/lib/database_consistency/checkers/base_checker.rb:25:in `report'
	from …/database_consistency-1.1.5/lib/database_consistency/checkers/base_checker.rb:34:in `report_if_enabled?'
	from …/database_consistency-1.1.5/lib/database_consistency/processors/validators_fractions_processor.rb:23:in `block (3 levels) in check'
	from …/database_consistency-1.1.5/lib/database_consistency/processors/validators_fractions_processor.rb:21:in `map'

Error in v 0.8.8

Rails: 6.0.3.4
Postgres: 12.4

<===begin===>
�[1mTraceback�[m (most recent call last):
	39: from /Users/usman/.rbenv/versions/2.7.1/bin/bundle:23:in `<main>'
	38: from /Users/usman/.rbenv/versions/2.7.1/bin/bundle:23:in `load'
	37: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/exe/bundle:34:in `<top (required)>'
	36: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/friendly_errors.rb:123:in `with_friendly_errors'
	35: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/exe/bundle:46:in `block in <top (required)>'
	34: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/cli.rb:24:in `start'
	33: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/vendor/thor/lib/thor/base.rb:476:in `start'
	32: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/cli.rb:30:in `dispatch'
	31: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/vendor/thor/lib/thor.rb:399:in `dispatch'
	30: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
	29: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
	28: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/cli.rb:476:in `exec'
	27: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/cli/exec.rb:28:in `run'
	26: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/cli/exec.rb:63:in `kernel_load'
	25: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/cli/exec.rb:63:in `load'
	24: from /Users/usman/.rbenv/versions/2.7.1/bin/database_consistency:23:in `<top (required)>'
	23: from /Users/usman/.rbenv/versions/2.7.1/bin/database_consistency:23:in `load'
	22: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/bin/database_consistency:44:in `<top (required)>'
	21: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency.rb:47:in `run'
	20: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/base_processor.rb:12:in `reports'
	19: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/base_processor.rb:12:in `flat_map'
	18: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/base_processor.rb:12:in `each'
	17: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/base_processor.rb:13:in `block in reports'
	16: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/base_processor.rb:28:in `reports'
	15: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:15:in `check'
	14: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:15:in `flat_map'
	13: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:15:in `each'
	12: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:18:in `block in check'
	11: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:18:in `flat_map'
	10: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:18:in `each'
	 9: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:19:in `block (2 levels) in check'
	 8: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:19:in `map'
	 7: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:21:in `block (3 levels) in check'
	 6: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/checkers/base_checker.rb:34:in `report_if_enabled?'
	 5: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/checkers/base_checker.rb:25:in `report'
	 4: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:40:in `check'
	 3: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:85:in `associated_column'
	 2: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:71:in `associated_key'
	 1: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/reflection.rb:472:in `active_record_primary_key'
/Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/reflection.rb:322:in `primary_key': �[1mUnknown primary key for table favorites in model Favorite. (�[1;4mActiveRecord::UnknownPrimaryKey�[m�[1m)�[m
<===end===>
<===begin===>
�[1mTraceback�[m (most recent call last):
	39: from /Users/usman/.rbenv/versions/2.7.1/bin/bundle:23:in `<main>'
	38: from /Users/usman/.rbenv/versions/2.7.1/bin/bundle:23:in `load'
	37: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/exe/bundle:34:in `<top (required)>'
	36: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/friendly_errors.rb:123:in `with_friendly_errors'
	35: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/exe/bundle:46:in `block in <top (required)>'
	34: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/cli.rb:24:in `start'
	33: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/vendor/thor/lib/thor/base.rb:476:in `start'
	32: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/cli.rb:30:in `dispatch'
	31: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/vendor/thor/lib/thor.rb:399:in `dispatch'
	30: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
	29: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
	28: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/cli.rb:476:in `exec'
	27: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/cli/exec.rb:28:in `run'
	26: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/cli/exec.rb:63:in `kernel_load'
	25: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/cli/exec.rb:63:in `load'
	24: from /Users/usman/.rbenv/versions/2.7.1/bin/database_consistency:23:in `<top (required)>'
	23: from /Users/usman/.rbenv/versions/2.7.1/bin/database_consistency:23:in `load'
	22: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/bin/database_consistency:44:in `<top (required)>'
	21: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency.rb:47:in `run'
	20: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/base_processor.rb:12:in `reports'
	19: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/base_processor.rb:12:in `flat_map'
	18: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/base_processor.rb:12:in `each'
	17: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/base_processor.rb:13:in `block in reports'
	16: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/base_processor.rb:28:in `reports'
	15: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:15:in `check'
	14: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:15:in `flat_map'
	13: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:15:in `each'
	12: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:18:in `block in check'
	11: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:18:in `flat_map'
	10: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:18:in `each'
	 9: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:19:in `block (2 levels) in check'
	 8: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:19:in `map'
	 7: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:21:in `block (3 levels) in check'
	 6: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/checkers/base_checker.rb:34:in `report_if_enabled?'
	 5: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/checkers/base_checker.rb:25:in `report'
	 4: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:40:in `check'
	 3: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:85:in `associated_column'
	 2: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:71:in `associated_key'
	 1: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/reflection.rb:472:in `active_record_primary_key'
/Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/activerecord-6.0.3.4/lib/active_record/reflection.rb:322:in `primary_key': �[1mUnknown primary key for table favorites in model Favorite. (�[1;4mActiveRecord::UnknownPrimaryKey�[m�[1m)�[m
<===end===>
<===begin===>
�[1mTraceback�[m (most recent call last):
	37: from /Users/usman/.rbenv/versions/2.7.1/bin/bundle:23:in `<main>'
	36: from /Users/usman/.rbenv/versions/2.7.1/bin/bundle:23:in `load'
	35: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/exe/bundle:34:in `<top (required)>'
	34: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/friendly_errors.rb:123:in `with_friendly_errors'
	33: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/exe/bundle:46:in `block in <top (required)>'
	32: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/cli.rb:24:in `start'
	31: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/vendor/thor/lib/thor/base.rb:476:in `start'
	30: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/cli.rb:30:in `dispatch'
	29: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/vendor/thor/lib/thor.rb:399:in `dispatch'
	28: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
	27: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
	26: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/cli.rb:476:in `exec'
	25: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/cli/exec.rb:28:in `run'
	24: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/cli/exec.rb:63:in `kernel_load'
	23: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/site_ruby/2.7.0/bundler/cli/exec.rb:63:in `load'
	22: from /Users/usman/.rbenv/versions/2.7.1/bin/database_consistency:23:in `<top (required)>'
	21: from /Users/usman/.rbenv/versions/2.7.1/bin/database_consistency:23:in `load'
	20: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/bin/database_consistency:44:in `<top (required)>'
	19: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency.rb:47:in `run'
	18: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/base_processor.rb:12:in `reports'
	17: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/base_processor.rb:12:in `flat_map'
	16: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/base_processor.rb:12:in `each'
	15: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/base_processor.rb:13:in `block in reports'
	14: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/base_processor.rb:28:in `reports'
	13: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:15:in `check'
	12: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:15:in `flat_map'
	11: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:15:in `each'
	10: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:18:in `block in check'
	 9: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:18:in `flat_map'
	 8: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:18:in `each'
	 7: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:19:in `block (2 levels) in check'
	 6: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:19:in `map'
	 5: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/processors/associations_processor.rb:21:in `block (3 levels) in check'
	 4: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/checkers/base_checker.rb:34:in `report_if_enabled?'
	 3: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/checkers/base_checker.rb:25:in `report'
	 2: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:40:in `check'
	 1: from /Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:85:in `associated_column'
/Users/usman/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/database_consistency-0.8.8/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:99:in `column': �[1mAssociation (country) of class (Users::Customer) relies on field (id) of table (public.countries) but it is missing. (�[1;4mDatabaseConsistency::Errors::MissingField�[m�[1m)�[m
<===end===>

Confused by error message.

I have the following model:

class User < ApplicationRecord
  devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable

  validates :email, presence: true, length: { maximum: 255 }
  ...
end

and the following sql column:

	email varchar(255) default '' not null,

When I run the gem, I get the error:

fail User email column is required but there is possible null value insert

I'm confused because I have presence: true on the model and not null in the database, so it shouldn't be possible for a null value insert.

Add option to generate todo file

Adopting this does not work when I have to fix 100s of validations errors in the initial setup PR

bundle exec database_consistency --todo
... should print:
User:
  email:
    ColumnPresenceChecker:
      enabled: false

A way to exclude some fails on per-file basis?

Hello.
This is a nice gem and I'd like to try it in our project. However as it turned out we have quite many fails. Because of that we would like to have some way to mark them all excluded (similar to rubocop_todo.yml) and integrate this gem into our CI tool so we can fix them later one by one. This approach would ensure we don't introduce new fails while we are fixing the old ones. Unfortunately I can't see a way to exclude fails on per-file (per-model) basis right now. Maybe there are plans for this? :)

Can't get it to work

Can't seem to get this gem to work on Rails 6. I have a mailbox model with a locale field, that has not null constraint on the DB but no presence validation.

class Mailbox < ApplicationRecord
  belongs_to :voicemail
end
# Table name: mailboxes
#
#  id           :bigint(8)        not null, primary key
#  locale       :string           not null
#  created_at   :datetime         not null
#  updated_at   :datetime         not null
#  voicemail_id :bigint(8)
irb(main):004:0> Mailbox._validators
=> {:voicemail=>[#<ActiveRecord::Validations::PresenceValidator:0x00007fa2300baa98 @attributes=[:voicemail], @options={:message=>:required}>]}
% bundle exec database_consistency
warning package.json: No license field
warning No license field

That's all it gives, some stuff about webpacker. No fail that mailbox doesn't have presence validation for locale. This is just one case. I have many other issues I was hoping this gem would find, but doesn't see to want to find anything.

What am I missing?

Idea: Replace `dependent: :delete`/`dependent: :nullify` with FK `on_delete:`/`on_update:`

Hey @djezzzl ! 👋

Cascade deletion is sometimes a very expensive operation.
In case the association is defined as dependent: :delete, it is possible to rely on the database to perform the deletion instead.
See :on_delete/:on_update.

Disclaimer: I clearly understand that dependent: :destroy should remain ignored, as destroy also runs callbacks.

Would it make sense to detect this and suggest changing the FK in such a way that the DB handles cascade deletion/nullification?

Sorry for not being verbose. I'd love to validate the idea with you first, and elaborate if you support it.

Originally posted in the wrong repo: toptal/database_validations#59

false positive for validation with condition

Hi, it seems it will check the validation even though we have a condition
Like this

validates :code, presence: true, on: :update

It fails even though it validates only on update.

Is it a known/wanted behavior?

Thanks

Recommend citext for `case_sensitive: false` validated fields

Does it make sense to do so?

https://www.postgresql.org/docs/13/citext.html has a good rationale for using citext. It's a useful feature for columns like, e.g. emails.

Regarding performance - should be faster compared to LOWER() indexes:

citext is not as efficient as text because the operator functions and the B-tree comparison functions must make copies of the data and convert it to lower case for comparisons. Also, only text can support B-Tree deduplication. However, citext is slightly more efficient than using lower to get case-insensitive matching.

❓ How to detect when a column is a good candidate for citext?

`belongs_to ... optional: false` with no `NOT NULL` column is not detected

Hey @djezzzl ! Me again 😄

Database consistency is missing (unless I'm missing something among a ton of things that it does detect) if an FK column is not marked as null: false (NOT NULL) in the DB schema, while it's belongs_to without optional: false.
optional: true became the default in Rails 4.2 if I'm not mistaken.

# app/models/books.rb
class Books < ApplicationRecord
  belongs_to :user
end
# db/schema.rb
  create_table "books", force: :cascade do |t|
    t.bigint "user_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["user_id"], name: "index_books_on_user_id"
  end

...

  add_foreign_key "books", "users"
# INSERT books (created_at, updated_at) values ('2021-01-01', '2021-01-01');
INSERT 0 1
Time: 4.294 ms
# SELECT * from books;
-[ RECORD 1 ]------------+--------------------
id                       | 1
user_id                  | [NULL]
created_at               | 2021-01-01 00:00:00
updated_at               | 2021-01-01 00:00:00

💥

I'll be happy to contribute such a check.

Custom validatios

Hi I install the tool today and founy 986 failures. Maybe some are false positive. Any way very nice tool. Found it from Evil Marintins notes. https://github.com/evilmartians/terraforming-rails

When I first ran it it failed. I open the gem to peak in.
We have a custom validator witch does not have an attribute.

# app/models/invoice_transcription.rb
class InvoiceTranscription < ApplicationRecord
  validates_with CustomerCarAndCarRegistrationValidator
end

# app/validators/customer_car_and_car_registration_validator.rb
class CustomerCarAndCarRegistrationValidator < ActiveModel::Validator
  def validate record
    return if record.customer_car_id.blank? == record.customer_car_registration_id.blank?
    record.errors.add :customer_car_id, message: I18n.t(:car_id_and_car_registration_id_required)
  end
end

I patched validators_processor.rb little and then it worked. I dont think this is the cleanes patch we could come up with.

# lib/database_consistency/processors/validators_processor.rb

# from
  validator.attributes.flat_map do |attribute|

# to
  (validator.attributes rescue []).flat_map do |attribute|

Can we fix this?

HABTM Native Functionality Not Valid

I am getting this error for a basic model that has a standard HABTM association. This requires me to manually specify the model instead of using the Rails built in methods.

fail HABTM_Categories article_id column is required in the database but do not have presence validator

For example:

class Category < ApplicationRecord
  has_and_belongs_to_many :articles
end
class Article < ApplicationRecord
  has_and_belongs_to_many :categories
end

This fails because the join table has a null: false in the migration but the generated join model in Rails doesn't have the validates :article_id, presence: true validation.

Suggestion: Maybe ignore habtm methods used in rails as its automatically generated?

Check that `belongs_to` defines an unconditional presence validator if the link column is required in the DB

Expand NullConstaintChecker so that if a link column (e.g. user_id) is required in the database, then the belongs_to association should be required: true/optional: false (an unconditional presence validation is defined).

This is a counter version enhancement for the suggested change in #90 and implemented in #96:

Expand ColumnPresenceChecker to check if the validation that covers belongs_to association has that column covered with non-null constraint.

As discussed here.

Consider adding Numericality validator to NullConstraintChecker?

Hi, and first of all thanks for this gem, we had tremendous amount of alerts fixed in our codebase.

According to Rails documentation, numericality does not allow nil values by default. In our validations, we omit the presence validator in favor of numericality but database_consitency report a missing presence if these cases.

I don't really know if it would take much time to dig the source code of this gem and come with a PR on this matter. What do you think?

Version 0.8.5 raise error

Hello, after bump version to 0.8.5 I've an error:

<===begin===>
[1mTraceback�[m (most recent call last):
	24: from /home/dell/.rvm/gems/ruby-2.6.5/bin/ruby_executable_hooks:24:in `<main>'
	23: from /home/dell/.rvm/gems/ruby-2.6.5/bin/ruby_executable_hooks:24:in `eval'
	22: from /home/dell/.rvm/gems/ruby-2.6.5/bin/database_consistency:23:in `<main>'
	21: from /home/dell/.rvm/gems/ruby-2.6.5/bin/database_consistency:23:in `load'
	20: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/bin/database_consistency:44:in `<top (required)>'
	19: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency.rb:46:in `run'
	18: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:12:in `reports'
	17: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:12:in `flat_map'
	16: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:12:in `each'
	15: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:13:in `block in reports'
	14: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:28:in `reports'
	13: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:15:in `check'
	12: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:15:in `flat_map'
	11: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:15:in `each'
	10: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:18:in `block in check'
	 9: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:18:in `flat_map'
	 8: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:18:in `each'
	 7: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:19:in `block (2 levels) in check'
	 6: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:19:in `map'
	 5: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:21:in `block (3 levels) in check'
	 4: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/base_checker.rb:30:in `report_if_enabled?'
	 3: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/base_checker.rb:23:in `report'
	 2: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:32:in `check'
	 1: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:92:in `converted_type'
/home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:85:in `type': �[1mundefined method `sql_type' for nil:NilClass (�[1;4mNoMethodError�[m�[1m)�[m
<===end===>
<===begin===>
�[1mTraceback�[m (most recent call last):
	24: from /home/dell/.rvm/gems/ruby-2.6.5/bin/ruby_executable_hooks:24:in `<main>'
	23: from /home/dell/.rvm/gems/ruby-2.6.5/bin/ruby_executable_hooks:24:in `eval'
	22: from /home/dell/.rvm/gems/ruby-2.6.5/bin/database_consistency:23:in `<main>'
	21: from /home/dell/.rvm/gems/ruby-2.6.5/bin/database_consistency:23:in `load'
	20: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/bin/database_consistency:44:in `<top (required)>'
	19: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency.rb:46:in `run'
	18: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:12:in `reports'
	17: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:12:in `flat_map'
	16: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:12:in `each'
	15: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:13:in `block in reports'
	14: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:28:in `reports'
	13: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:15:in `check'
	12: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:15:in `flat_map'
	11: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:15:in `each'
	10: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:18:in `block in check'
	 9: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:18:in `flat_map'
	 8: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:18:in `each'
	 7: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:19:in `block (2 levels) in check'
	 6: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:19:in `map'
	 5: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:21:in `block (3 levels) in check'
	 4: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/base_checker.rb:30:in `report_if_enabled?'
	 3: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/base_checker.rb:23:in `report'
	 2: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:32:in `check'
	 1: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:92:in `converted_type'
/home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:85:in `type': �[1mundefined method `sql_type' for nil:NilClass (�[1;4mNoMethodError�[m�[1m)�[m
<===end===>
<===begin===>
�[1mTraceback�[m (most recent call last):
	24: from /home/dell/.rvm/gems/ruby-2.6.5/bin/ruby_executable_hooks:24:in `<main>'
	23: from /home/dell/.rvm/gems/ruby-2.6.5/bin/ruby_executable_hooks:24:in `eval'
	22: from /home/dell/.rvm/gems/ruby-2.6.5/bin/database_consistency:23:in `<main>'
	21: from /home/dell/.rvm/gems/ruby-2.6.5/bin/database_consistency:23:in `load'
	20: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/bin/database_consistency:44:in `<top (required)>'
	19: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency.rb:46:in `run'
	18: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:12:in `reports'
	17: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:12:in `flat_map'
	16: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:12:in `each'
	15: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:13:in `block in reports'
	14: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:28:in `reports'
	13: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:15:in `check'
	12: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:15:in `flat_map'
	11: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:15:in `each'
	10: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:18:in `block in check'
	 9: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:18:in `flat_map'
	 8: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:18:in `each'
	 7: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:19:in `block (2 levels) in check'
	 6: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:19:in `map'
	 5: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:21:in `block (3 levels) in check'
	 4: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/base_checker.rb:30:in `report_if_enabled?'
	 3: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/base_checker.rb:23:in `report'
	 2: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:32:in `check'
	 1: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:92:in `converted_type'
/home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:85:in `type': �[1mundefined method `sql_type' for nil:NilClass (�[1;4mNoMethodError�[m�[1m)�[m
<===end===>
<===begin===>
�[1mTraceback�[m (most recent call last):
	24: from /home/dell/.rvm/gems/ruby-2.6.5/bin/ruby_executable_hooks:24:in `<main>'
	23: from /home/dell/.rvm/gems/ruby-2.6.5/bin/ruby_executable_hooks:24:in `eval'
	22: from /home/dell/.rvm/gems/ruby-2.6.5/bin/database_consistency:23:in `<main>'
	21: from /home/dell/.rvm/gems/ruby-2.6.5/bin/database_consistency:23:in `load'
	20: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/bin/database_consistency:44:in `<top (required)>'
	19: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency.rb:46:in `run'
	18: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:12:in `reports'
	17: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:12:in `flat_map'
	16: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:12:in `each'
	15: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:13:in `block in reports'
	14: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:28:in `reports'
	13: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:15:in `check'
	12: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:15:in `flat_map'
	11: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:15:in `each'
	10: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:18:in `block in check'
	 9: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:18:in `flat_map'
	 8: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:18:in `each'
	 7: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:19:in `block (2 levels) in check'
	 6: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:19:in `map'
	 5: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:21:in `block (3 levels) in check'
	 4: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/base_checker.rb:30:in `report_if_enabled?'
	 3: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/base_checker.rb:23:in `report'
	 2: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:32:in `check'
	 1: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:92:in `converted_type'
/home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:85:in `type': �[1mundefined method `sql_type' for nil:NilClass (�[1;4mNoMethodError�[m�[1m)�[m
<===end===>
<===begin===>
�[1mTraceback�[m (most recent call last):
	24: from /home/dell/.rvm/gems/ruby-2.6.5/bin/ruby_executable_hooks:24:in `<main>'
	23: from /home/dell/.rvm/gems/ruby-2.6.5/bin/ruby_executable_hooks:24:in `eval'
	22: from /home/dell/.rvm/gems/ruby-2.6.5/bin/database_consistency:23:in `<main>'
	21: from /home/dell/.rvm/gems/ruby-2.6.5/bin/database_consistency:23:in `load'
	20: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/bin/database_consistency:44:in `<top (required)>'
	19: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency.rb:46:in `run'
	18: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:12:in `reports'
	17: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:12:in `flat_map'
	16: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:12:in `each'
	15: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:13:in `block in reports'
	14: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:28:in `reports'
	13: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:15:in `check'
	12: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:15:in `flat_map'
	11: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:15:in `each'
	10: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:18:in `block in check'
	 9: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:18:in `flat_map'
	 8: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:18:in `each'
	 7: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:19:in `block (2 levels) in check'
	 6: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:19:in `map'
	 5: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:21:in `block (3 levels) in check'
	 4: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/base_checker.rb:30:in `report_if_enabled?'
	 3: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/base_checker.rb:23:in `report'
	 2: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:32:in `check'
	 1: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:92:in `converted_type'
/home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:85:in `type': �[1mundefined method `sql_type' for nil:NilClass (�[1;4mNoMethodError�[m�[1m)�[m
<===end===>
<===begin===>
�[1mTraceback�[m (most recent call last):
	24: from /home/dell/.rvm/gems/ruby-2.6.5/bin/ruby_executable_hooks:24:in `<main>'
	23: from /home/dell/.rvm/gems/ruby-2.6.5/bin/ruby_executable_hooks:24:in `eval'
	22: from /home/dell/.rvm/gems/ruby-2.6.5/bin/database_consistency:23:in `<main>'
	21: from /home/dell/.rvm/gems/ruby-2.6.5/bin/database_consistency:23:in `load'
	20: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/bin/database_consistency:44:in `<top (required)>'
	19: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency.rb:46:in `run'
	18: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:12:in `reports'
	17: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:12:in `flat_map'
	16: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:12:in `each'
	15: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:13:in `block in reports'
	14: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/base_processor.rb:28:in `reports'
	13: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:15:in `check'
	12: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:15:in `flat_map'
	11: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:15:in `each'
	10: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:18:in `block in check'
	 9: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:18:in `flat_map'
	 8: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:18:in `each'
	 7: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:19:in `block (2 levels) in check'
	 6: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:19:in `map'
	 5: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/processors/associations_processor.rb:21:in `block (3 levels) in check'
	 4: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/base_checker.rb:30:in `report_if_enabled?'
	 3: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/base_checker.rb:23:in `report'
	 2: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:32:in `check'
	 1: from /home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:92:in `converted_type'
/home/dell/.rvm/gems/ruby-2.6.5/gems/database_consistency-0.8.5/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:85:in `type': �[1mundefined method `sql_type' for nil:NilClass ([1;4mNoMethodError�[m�[1m)[m
<===end===>

enum + validation consistency check

Hi :)

I've got quite few enum's in database and I've found few instances when the Rails enum was not set to include all DB enum values, this lead to reading the field as nil in case the value was missing in Rails enum.

Example:

  • schema: t.column "type", "enum('STONE','TREE')", default: "STONE"
  • model: enum type: { "STONE" => "STONE", "TREES" => "TREES"], _prefix: :type
  • validation: validate :type, inclusion: { in: %w[STONE TREES] } - actually if enum is synced then this can be smaller list, but still it can include something invalid for DB - like TREES - note the extra S.

Do you think it can make place into the gem?

Failure to find database table

Your tool looks perfect for our purpose of finding data inconsistencies - thanks! However, when I run it, I get the following error:

root@8b06bb2b49e8:/app# bundle exec database_consistency
Thank you for using the gem. Any contribution is welcome https://github.com/djezzzl/database_consistency!
(c) Evgeniy Demin <[email protected]>

/var/lib/gems/2.3.0/gems/activerecord-4.2.11/lib/active_record/connection_adapters/postgresql_adapter.rb:592:in `async_exec': PG::UndefinedTable: ERROR:  relation "version_associations" does not exist (ActiveRecord::StatementInvalid)
LINE 5:                WHERE a.attrelid = '"version_associations"'::...
                                          ^
:               SELECT a.attname, format_type(a.atttypid, a.atttypmod),
                     pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod
                FROM pg_attribute a LEFT JOIN pg_attrdef d
                  ON a.attrelid = d.adrelid AND a.attnum = d.adnum
               WHERE a.attrelid = '"version_associations"'::regclass
                 AND a.attnum > 0 AND NOT a.attisdropped
               ORDER BY a.attnum
	from /var/lib/gems/2.3.0/gems/activerecord-4.2.11/lib/active_record/connection_adapters/postgresql_adapter.rb:592:in `block in exec_no_cache'
	from /var/lib/gems/2.3.0/gems/activerecord-4.2.11/lib/active_record/connection_adapters/abstract_adapter.rb:484:in `block in log'
	from /var/lib/gems/2.3.0/gems/activesupport-4.2.11/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
	from /var/lib/gems/2.3.0/gems/activerecord-4.2.11/lib/active_record/connection_adapters/abstract_adapter.rb:478:in `log'
	from /var/lib/gems/2.3.0/gems/activerecord-4.2.11/lib/active_record/connection_adapters/postgresql_adapter.rb:592:in `exec_no_cache'
	from /var/lib/gems/2.3.0/gems/activerecord-4.2.11/lib/active_record/connection_adapters/postgresql_adapter.rb:584:in `execute_and_clear'
	from /var/lib/gems/2.3.0/gems/activerecord-4.2.11/lib/active_record/connection_adapters/postgresql/database_statements.rb:160:in `exec_query'
	from /var/lib/gems/2.3.0/gems/activerecord-4.2.11/lib/active_record/connection_adapters/postgresql_adapter.rb:733:in `column_definitions'
	from /var/lib/gems/2.3.0/gems/activerecord-4.2.11/lib/active_record/connection_adapters/postgresql/schema_statements.rb:197:in `columns'
	from /var/lib/gems/2.3.0/gems/activerecord-4.2.11/lib/active_record/connection_adapters/schema_cache.rb:43:in `columns'
	from /var/lib/gems/2.3.0/gems/activerecord-4.2.11/lib/active_record/attributes.rb:93:in `columns'
	from /var/lib/gems/2.3.0/gems/database_consistency-0.6.6/lib/database_consistency/processors/columns_processor.rb:15:in `block in check'
	from /var/lib/gems/2.3.0/gems/database_consistency-0.6.6/lib/database_consistency/processors/columns_processor.rb:14:in `each'
	from /var/lib/gems/2.3.0/gems/database_consistency-0.6.6/lib/database_consistency/processors/columns_processor.rb:14:in `flat_map'
	from /var/lib/gems/2.3.0/gems/database_consistency-0.6.6/lib/database_consistency/processors/columns_processor.rb:14:in `check'
	from /var/lib/gems/2.3.0/gems/database_consistency-0.6.6/lib/database_consistency/processors/base_processor.rb:27:in `reports'
	from /var/lib/gems/2.3.0/gems/database_consistency-0.6.6/lib/database_consistency/processors/base_processor.rb:12:in `block in reports'
	from /var/lib/gems/2.3.0/gems/database_consistency-0.6.6/lib/database_consistency/processors/base_processor.rb:11:in `each'
	from /var/lib/gems/2.3.0/gems/database_consistency-0.6.6/lib/database_consistency/processors/base_processor.rb:11:in `flat_map'
	from /var/lib/gems/2.3.0/gems/database_consistency-0.6.6/lib/database_consistency/processors/base_processor.rb:11:in `reports'
	from /var/lib/gems/2.3.0/gems/database_consistency-0.6.6/lib/database_consistency.rb:34:in `run'
	from /var/lib/gems/2.3.0/gems/database_consistency-0.6.6/bin/database_consistency:30:in `<top (required)>'
	from /usr/local/bin/database_consistency:22:in `load'
	from /usr/local/bin/database_consistency:22:in `<main>'

Examining the existing parent models, I see:

irb(main):008:0> ActiveRecord::Base.descendants.delete_if(&:abstract_class?).join(", ")
=> "DynamicAnnotation::Field, Dynamic, PaperTrail::Version, Bot::Viber, ProjectMedia, Bot::BridgeReader, Team, TeamTask, Task, Comment, Media, Bot::Slack, Embed, TeamUser, Project, Tag, Flag, Assignment, DynamicAnnotation::AnnotationType, ProjectSource, User, PaperTrail::VersionAssociation, Account, AccountSource, Annotation, ApiKey, Bot::Alegre, Bot::Bot, Bot::Facebook, Relationship, Bot::Twitter, Bounce, ClaimSource, Contact, DynamicAnnotation::FieldInstance, DynamicAnnotation::FieldType, Source, TagText, TeamBot, TeamBotInstallation, UploadedFile, Claim, Link, UploadedImage, BotUser"

which includes PaperTrail::VersionAssociation that the failure above is complaining about. However, this model is added by a 3rd-party gem and I would hate to debug through their code to find what's wrong. Would it make sense to add a config to exclude some models?

UniqueIndexChecker

Hi @djezzzl!
Thx for the gem

I was wondering if it would be possible to add the inverse of MissingUniqueIndexChecker, i.e. a way to detect unique index constraint which are present in the schema but missing in the model. Is this something that can be added?

I can look into it and work on a PR if that's something you'd be willing to merge, but I'd appreciate some pointers.

Thanks!

Incorrect numeric enum backing datatype - varchar/text

The problem only becomes apparent when prepared_statements: option is set to false. This is typical and recommended by Rails when connecting via PgBouncer.

ActiveRecord::StatementInvalid: PG::UndefinedFunction: ERROR:  operator
   does not exist: text = integer
      LINE 1: SELECT "users".* FROM "users" WHERE "users"."os" = 0
# app/models/user.rb
enum os: [:linux, :windows]
# db/schema.rb
  t.text "os"

The data actually saved in the column is '1', '2' etc.

With prepared_statements: true this error doesn't happen, and it works as expected (well, not really expected, I would expect it to blow up in both cases, but there's an implicit conversion somewhere along the way in statement preparation).

Should be easy to detect for both

enum os: [:linux, :windows]

and

enum os: { linux: 1, windows: 2}

definition options.

Checks fail with error due to association to non-existing model/table

Hi,

I am using version 0.7.1 and bundle exec database_consistency is generating an error report that looks like this:

<===begin===>
Traceback (most recent call last):
	26: from /home/matthieu/.rvm/gems/ruby-2.6.0/bin/ruby_executable_hooks:24:in `<main>'
	25: from /home/matthieu/.rvm/gems/ruby-2.6.0/bin/ruby_executable_hooks:24:in `eval'
	24: from /home/matthieu/.rvm/gems/ruby-2.6.0/bin/database_consistency:23:in `<main>'
	23: from /home/matthieu/.rvm/gems/ruby-2.6.0/bin/database_consistency:23:in `load'
	22: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/database_consistency-0.7.1/bin/database_consistency:26:in `<top (required)>'
	21: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/database_consistency-0.7.1/lib/database_consistency.rb:34:in `run'
	20: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/database_consistency-0.7.1/lib/database_consistency/processors/base_processor.rb:11:in `reports'
	19: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/database_consistency-0.7.1/lib/database_consistency/processors/base_processor.rb:11:in `flat_map'
	18: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/database_consistency-0.7.1/lib/database_consistency/processors/base_processor.rb:11:in `each'
	17: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/database_consistency-0.7.1/lib/database_consistency/processors/base_processor.rb:12:in `block in reports'
	16: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/database_consistency-0.7.1/lib/database_consistency/processors/base_processor.rb:27:in `reports'
	15: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/database_consistency-0.7.1/lib/database_consistency/processors/associations_processor.rb:14:in `check'
	14: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/database_consistency-0.7.1/lib/database_consistency/processors/associations_processor.rb:14:in `flat_map'
	13: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/database_consistency-0.7.1/lib/database_consistency/processors/associations_processor.rb:14:in `each'
	12: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/database_consistency-0.7.1/lib/database_consistency/processors/associations_processor.rb:17:in `block in check'
	11: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/database_consistency-0.7.1/lib/database_consistency/processors/associations_processor.rb:17:in `flat_map'
	10: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/database_consistency-0.7.1/lib/database_consistency/processors/associations_processor.rb:17:in `each'
	 9: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/database_consistency-0.7.1/lib/database_consistency/processors/associations_processor.rb:18:in `block (2 levels) in check'
	 8: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/database_consistency-0.7.1/lib/database_consistency/processors/associations_processor.rb:18:in `map'
	 7: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/database_consistency-0.7.1/lib/database_consistency/processors/associations_processor.rb:20:in `block (3 levels) in check'
	 6: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/database_consistency-0.7.1/lib/database_consistency/checkers/base_checker.rb:30:in `report_if_enabled?'
	 5: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/database_consistency-0.7.1/lib/database_consistency/checkers/base_checker.rb:23:in `report'
	 4: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/database_consistency-0.7.1/lib/database_consistency/checkers/association_checkers/missing_index_checker.rb:28:in `check'
	 3: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/database_consistency-0.7.1/lib/database_consistency/checkers/association_checkers/missing_index_checker.rb:36:in `index'
	 2: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/activerecord-5.2.2.1/lib/active_record/reflection.rb:379:in `klass'
	 1: from /home/matthieu/.rvm/gems/ruby-2.6.0/gems/activerecord-5.2.2.1/lib/active_record/reflection.rb:422:in `compute_class'
/home/matthieu/.rvm/gems/ruby-2.6.0/gems/activerecord-5.2.2.1/lib/active_record/inheritance.rb:196:in `compute_type': uninitialized constant User::OldTable (NameError)
<===end===>

The source of the error is because I have an association is the user model to a model that has been deleted since (has_one :old_table, dependent: :restrict_with_exception).

Also would it be possible to return an exit code 1 when some checks fail with an error? I am currently using the gem as part of my automated tests on Travis and I won't necessarily see the error if the build returns 0.

Thanks for everything, the gem has been really helpful to me so far!

Unexpected exit codes

Hi there,

First of all, thanks so much for this gem. It's going to be incredibly useful to our team for maintaining best practices. To that effect, I'm implementing it into our CI/CD pipelines, and noticed the following:

If there are no errors, the exit status is a failure:

> bundle exec database_consistency

> echo $?                                             
1

If there are failures, the exit status is a failure:

> bundle exec database_consistency
fail User lunch_option_attendances associated model should have proper index in the database

> echo $?
1

Is there any way to either add a flag or default behavior to give a success exit code if no errors are found, and otherwise give a failing exit code?

Currently, my workaround is to negate a grep for the word fail. It works, but isn't super elegant:
! bundle exec database_consistency | grep fail

Issue with custom foreign key

database_consistency reports an error with one of our model relationships:

class FormRequest < ApplicationRecord
  # t.integer "status_id", null: false
  belongs_to :status, inverse_of: :form_requests, class_name: 'FormRequestStatus'
end

class FormRequestStatus < ApplicationRecord
  has_many :form_requests, inverse_of: :status
end

Error:

<===begin===>
Traceback (most recent call last):
	24: from /home/fletch/.rvm/gems/ruby-2.7.4/bin/ruby_executable_hooks:22:in `<main>'
	23: from /home/fletch/.rvm/gems/ruby-2.7.4/bin/ruby_executable_hooks:22:in `eval'
	22: from /home/fletch/.rvm/gems/ruby-2.7.4/bin/database_consistency:23:in `<main>'
	21: from /home/fletch/.rvm/gems/ruby-2.7.4/bin/database_consistency:23:in `load'
	20: from /home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/bin/database_consistency:44:in `<top (required)>'
	19: from /home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/lib/database_consistency.rb:53:in `run'
	18: from /home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/lib/database_consistency/processors/base_processor.rb:13:in `reports'
	17: from /home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/lib/database_consistency/processors/base_processor.rb:13:in `flat_map'
	16: from /home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/lib/database_consistency/processors/base_processor.rb:13:in `each'
	15: from /home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/lib/database_consistency/processors/base_processor.rb:14:in `block in reports'
	14: from /home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/lib/database_consistency/processors/base_processor.rb:29:in `reports'
	13: from /home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/lib/database_consistency/processors/associations_processor.rb:15:in `check'
	12: from /home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/lib/database_consistency/processors/associations_processor.rb:15:in `flat_map'
	11: from /home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/lib/database_consistency/processors/associations_processor.rb:15:in `each'
	10: from /home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/lib/database_consistency/processors/associations_processor.rb:18:in `block in check'
	 9: from /home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/lib/database_consistency/processors/associations_processor.rb:18:in `flat_map'
	 8: from /home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/lib/database_consistency/processors/associations_processor.rb:18:in `each'
	 7: from /home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/lib/database_consistency/processors/associations_processor.rb:19:in `block (2 levels) in check'
	 6: from /home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/lib/database_consistency/processors/associations_processor.rb:19:in `map'
	 5: from /home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/lib/database_consistency/processors/associations_processor.rb:21:in `block (3 levels) in check'
	 4: from /home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/lib/database_consistency/checkers/base_checker.rb:34:in `report_if_enabled?'
	 3: from /home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/lib/database_consistency/checkers/base_checker.rb:25:in `report'
	 2: from /home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:40:in `check'
	 1: from /home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:85:in `associated_column'
/home/fletch/.rvm/gems/ruby-2.7.4/gems/database_consistency-1.1.1/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:99:in `column': Association (form_requests) of class (FormRequestStatus) relies on field (form_request_status_id) of table (form_requests) but it is missing. (DatabaseConsistency::Errors::MissingField)
<===end===>

Happy to provide any additional information that might help debugging. These models are heavily used in our application, so I'm confident they are working.

global ignore not working

I followed the rails install and got it running ... there is too much, so I need to ignore 90%
so I added to .database_consistency.yml

RedundantIndexChecker:
  enabled: false

... but bundle exec database_consistency still shows:

RedundantIndexChecker fail ProductProject index_product_projects_on_project_id index is redundant as (index_product_projects_on_project_id_and_product_id) covers it

(individual ignores work though)

Trouble understanding config file syntax

Hi,

I'm having trouble understanding the expected config syntax, and whether what I'm seeing is a bug (or more likely a problem with my setup). Can I just confirm the behaviour of the following config files?

All:
  enabled: false

☝️ this will disable all checkers for all models - is that right?

UniqueIndexChecker:
  enabled: false

☝️ this will disable the UniqueIndexChecker for all models - is that right?

Currently neither of these are working for me. I wonder if perhaps the functionality I'm assuming above doesn't actually exist, and whether all config has to start with a model name? I'd be grateful if you could confirm either way.

Many thanks!

Failure log when having functional indexes

bundle exec database_consistency generates a failure log (just a file named database_consistency_<date>_<and>_<time>) containing the following line:

/bundle/gems/database_consistency-0.6.5/lib/database_consistency/checkers/missing_unique_index_checker.rb:36:in `block in unique_index': �[1mundefined method `sort' for "lower((email)::text)":String (�[1;4mNoMethodError�[m�[1m)�[m

Support for official Rails 6 Release

Thanks so much for this wonderful gem.

It looks like this isn't compatible with Rails 6 official that was released yesterday:
spec.add_dependency 'activerecord', '>= 3.2', '< 6'

Is this intentional? I've been running it with the RC1/RC2 releases without issue.

False positive on array length

Hello,

So I have this model with an array field like this :

t.string "content", limit: 255, array: true

It causes the length validator to raise, but it's not correct, since the database validation is that every element of that array isn't bigger than 255, not the array itself. Is this behavior wanted ? I think that the only way to validate this is to have a custom validator, and i'm not sure that it would prevent database_consistency to complain ?

skip ForeignKeyChecker for rails 6+ multiple databases setup

ForeignKeyChecker should ignore when the underlying association tables belong to different databases, since a foreign key cannot be defined here.

production:
  primary:
    database: my_primary_database
  animals:
    database: my_animals_database
    migrations_paths: db/animals_migrate
class User < ApplicationRecord
  has_many :dogs
end

class AnimalsRecord < ApplicationRecord
  self.abstract_class = true
  connects_to database: { writing: :animals, reading: :animals }
end

class Dog < AnimalsRecord
  belongs_to :user
end

ForeignKeyChecker fail Dog User should have foreign key in the database

Repurpose BelongsToPresenceChecker to check for foreign key presence in the DB

Problem

BelongsToPresenceChecker shouldn't care if an association has required: true because any non-polymorphic belongs_to should have foreign keys and nulls are okay with that.

We have to rename the checker as it simply does slightly different than "belongs_to presence".

Suggested approach

  1. Make BelongsToPresenceChecker to be derived from AssociationChecker and check if belongs_to has a foreign key.
  2. Rename the checker.

As discussed here

Idea: checker for unique index for has_one associations

Currently there exists 2 things in database_consistency:

  • a MissingUniqueIndexChecker that checks that uniqueness validations have a unique index in the DB
  • a MissingIndexChecker that checks that an index exists for has_one and has_many associations

I think in the has_one case, we should enforce that there should be a unique index on exactly the columns of the associations, so that the DB guarantees that this has_one remains a has_one and doesn't become a has_many.

I believe it would be hard to integrate this feature in MissingUniqueIndexChecker as this one inherits ValidatorChecker, and I'm unsure if it should be part of MissingIndexChecker or split this one into two checkers for has_many (which the current behavior) and for has_one (which would be even stricter).

CC @frantisekrokusek

Let me know what you think and which path you'd rather have this implemented, thanks

false MissingIndexChecker report on double column unique index with a through on join object.

Sorry if i'm wrong but...

With the following models:

class User
  has_many  :rules
end

class Thing
  has_many  :rules
  has_many :users, through: :rules
end

class Rule
 belong_to :user
 belong_to :thing
end

After adding a unique index on 2 columns

add_index :rules, %i[user_id, thing_id], unique: true

Then i get:

MissingIndexChecker fail Thing rules associated model should have proper index in the database ...

Running Postgresql EXPLAIN show the defined index is used as expected.

First i extracted the has_many through SQL:

[5] pry(main)> Thing.last.users.to_sql
=> "SELECT \"users\".* FROM \"users\" INNER JOIN \"rules\" ON \"users\".\"id\" = \"rules\".\"user_id\" WHERE \"rules\".\"thing_id\" = 88611"

Then i checked that defined index were correctly used:

EXPLAIN SELECT users.* FROM users INNER JOIN rules ON users.id = rules.user_id WHERE rules.thing_id = 8861 ;

Which gave me the following result:

                                                                QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=0.70..1355.76 rows=1 width=362)
   ->  Index Only Scan using index_rules_on_user_id_and_thing_id on rules  (cost=0.41..1347.45 rows=1 width=8)
         Index Cond: (thing_id = 8861)
   ->  Index Scan using users_pkey on users  (cost=0.29..8.30 rows=1 width=362)
         Index Cond: (id = rules.user_id)
(5 rows)

Same problem occurs on polymorphic relationships backed by a unique index on the _id and _type columns.

Ignore Rails 6 warnings concerning ActionText and ActiveStorage models

Hi, thanks for the useful gem!

I'm using Rails 6.0.2.1 with ActiveStorage and ActionText (I don't think I did anything special during my Rails install), yet database_consistency reports the following failures:

fail ActionText::RichText name column is required in the database but do not have presence validator
fail ActiveStorage::Attachment name column is required in the database but do not have presence validator
fail ActiveStorage::Blob key column is required in the database but do not have presence validator
fail ActiveStorage::Blob filename column is required in the database but do not have presence validator
fail ActiveStorage::Blob byte_size column is required in the database but do not have presence validator
fail ActiveStorage::Blob checksum column is required in the database but do not have presence validator

I ignored them by adding the following code to my .database_consistency.yml but I'm thinking that this could be added to a generator, or to the Rails6 example.

ActionText::RichText:
  enabled: false
ActiveStorage::Attachment:
  enabled: false
ActiveStorage::Blob:
  enabled: false

Let me know what you think would be best, I could try my hand at a PR if needed.

False positive for unique index

Hi, we recently encountered this problem:

in the code we have the following, and package_type is a relation

validates :zipcode, uniqueness: { scope: [:package_type] }

And in the database, we have the unique index
index_blacklist_zipcodes_on_package_type_id_and_zipcode (package_type_id,zipcode) UNIQUE

But the gem does not recognize it, because in the validation, we didn't write package_type_id

Do you think this can be something easy to fix?

Thanks a lot

Does the gem support multiple databases?

Hi,

Gem looks great, and I'd love to try it out, but I'm getting the error below. This suggests that the gem is having trouble with more than one database in database.yml, as it is looking for a table on the primary database that is only available on the secondary database. Is this expected behaviour, as multiple databases are not supported?

(In log extract below I have changed the names of the actual primary database to primary_database and the actual table to table_on_secondary_database for clarity)

/usr/local/bundle/gems/mysql2-0.5.3/lib/mysql2/client.rb:131:in `_query': Mysql2::Error: Table 'primary_database.table_on_secondary_database' doesn't exist (ActiveRecord::StatementInvalid)
        from /usr/local/bundle/gems/mysql2-0.5.3/lib/mysql2/client.rb:131:in `block in query'
        from /usr/local/bundle/gems/mysql2-0.5.3/lib/mysql2/client.rb:130:in `handle_interrupt'
        from /usr/local/bundle/gems/mysql2-0.5.3/lib/mysql2/client.rb:130:in `query'
        from /usr/local/bundle/gems/rack-mini-profiler-2.3.3/lib/patches/db/mysql2/alias_method.rb:22:in `query'
        from /usr/local/bundle/gems/activerecord-6.1.6.1/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:206:in `block (2 levels) in execute'
        from /usr/local/bundle/gems/activesupport-6.1.6.1/lib/active_support/dependencies/interlock.rb:48:in `block in permit_concurrent_loads'
        from /usr/local/bundle/gems/activesupport-6.1.6.1/lib/active_support/concurrency/share_lock.rb:187:in `yield_shares'
        from /usr/local/bundle/gems/activesupport-6.1.6.1/lib/active_support/dependencies/interlock.rb:47:in `permit_concurrent_loads'
        from /usr/local/bundle/gems/activerecord-6.1.6.1/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:205:in `block in execute'
        from /usr/local/bundle/gems/activerecord-6.1.6.1/lib/active_record/connection_adapters/abstract_adapter.rb:696:in `block (2 levels) in log'
        from /usr/local/bundle/gems/activesupport-6.1.6.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:26:in `block (2 levels) in synchronize'
        from /usr/local/bundle/gems/activesupport-6.1.6.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt'
        from /usr/local/bundle/gems/activesupport-6.1.6.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize'
        from /usr/local/bundle/gems/activesupport-6.1.6.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'
        from /usr/local/bundle/gems/activesupport-6.1.6.1/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'
        from /usr/local/bundle/gems/activerecord-6.1.6.1/lib/active_record/connection_adapters/abstract_adapter.rb:695:in `block in log'
        from /usr/local/bundle/gems/activesupport-6.1.6.1/lib/active_support/notifications/instrumenter.rb:24:in `instrument'
        from /usr/local/bundle/gems/activerecord-6.1.6.1/lib/active_record/connection_adapters/abstract_adapter.rb:687:in `log'
        from /usr/local/bundle/gems/activerecord-6.1.6.1/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:204:in `execute'
        from /usr/local/bundle/gems/activerecord-6.1.6.1/lib/active_record/connection_adapters/mysql/database_statements.rb:52:in `execute'
        from /usr/local/bundle/gems/marginalia-1.11.1/lib/marginalia.rb:71:in `execute_with_marginalia'
        from /usr/local/bundle/gems/activerecord-6.1.6.1/lib/active_record/connection_adapters/abstract_mysql_adapter.rb:215:in `execute_and_free'
        from /usr/local/bundle/gems/activerecord-6.1.6.1/lib/active_record/connection_adapters/mysql/schema_statements.rb:11:in `indexes'
        from /usr/local/bundle/gems/database_consistency-1.1.15/lib/database_consistency/processors/indexes_processor.rb:19:in `block in check'
        from /usr/local/bundle/gems/database_consistency-1.1.15/lib/database_consistency/processors/indexes_processor.rb:16:in `each'
        from /usr/local/bundle/gems/database_consistency-1.1.15/lib/database_consistency/processors/indexes_processor.rb:16:in `flat_map'
        from /usr/local/bundle/gems/database_consistency-1.1.15/lib/database_consistency/processors/indexes_processor.rb:16:in `check'
        from /usr/local/bundle/gems/database_consistency-1.1.15/lib/database_consistency/processors/base_processor.rb:29:in `reports'
        from /usr/local/bundle/gems/database_consistency-1.1.15/lib/database_consistency/processors/base_processor.rb:14:in `block in reports'
        from /usr/local/bundle/gems/database_consistency-1.1.15/lib/database_consistency/processors/base_processor.rb:13:in `each'
        from /usr/local/bundle/gems/database_consistency-1.1.15/lib/database_consistency/processors/base_processor.rb:13:in `flat_map'
        from /usr/local/bundle/gems/database_consistency-1.1.15/lib/database_consistency/processors/base_processor.rb:13:in `reports'
        from /usr/local/bundle/gems/database_consistency-1.1.15/lib/database_consistency.rb:53:in `run'
        from /usr/local/bundle/gems/database_consistency-1.1.15/bin/database_consistency:69:in `<top (required)>'
        from /usr/local/bundle/bin/database_consistency:25:in `load'
        from /usr/local/bundle/bin/database_consistency:25:in `<top (required)>'
        from /usr/local/bundle/gems/bundler-2.3.14/lib/bundler/cli/exec.rb:58:in `load'
        from /usr/local/bundle/gems/bundler-2.3.14/lib/bundler/cli/exec.rb:58:in `kernel_load'
        from /usr/local/bundle/gems/bundler-2.3.14/lib/bundler/cli/exec.rb:23:in `run'
        from /usr/local/bundle/gems/bundler-2.3.14/lib/bundler/cli.rb:483:in `exec'
        from /usr/local/bundle/gems/bundler-2.3.14/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
        from /usr/local/bundle/gems/bundler-2.3.14/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
        from /usr/local/bundle/gems/bundler-2.3.14/lib/bundler/vendor/thor/lib/thor.rb:392:in `dispatch'
        from /usr/local/bundle/gems/bundler-2.3.14/lib/bundler/cli.rb:31:in `dispatch'
        from /usr/local/bundle/gems/bundler-2.3.14/lib/bundler/vendor/thor/lib/thor/base.rb:485:in `start'
        from /usr/local/bundle/gems/bundler-2.3.14/lib/bundler/cli.rb:25:in `start'
        from /usr/local/bundle/gems/bundler-2.3.14/exe/bundle:48:in `block in <top (required)>'
        from /usr/local/bundle/gems/bundler-2.3.14/lib/bundler/friendly_errors.rb:103:in `with_friendly_errors'
        from /usr/local/bundle/gems/bundler-2.3.14/exe/bundle:36:in `<top (required)>'
        from /api/bin/bundle:113:in `load'
        from /api/bin/bundle:113:in `<main>'

In the model that is throwing the error, we have the database defined as follows (names changed for clarity):

  class SecondaryDatabaseRecord < SecondaryDatabaseApplicationRecord
    self.table_name = "table_on_secondary_database"

Thanks!

LengthConstraintChecker with Integer and BigInt

I am using Rails with Postgres and I get this errors for all my models:

fail MyModel id column has limit in the database but do not have length validator
fail MyModel my_other_model_id column has limit in the database but do not have length validator
fail MyOtherModel things_count column has limit in the database but do not have length validator

In the schema, all those values are default :bigint(8) and :integer. Is it a good practice to add a validator for, for instance, the ids? I think it isn't.

By the way, for what I've seen, with Postgres, ActiveRecord defines the sql_type_metadata of BigInt as #<ActiveRecord::ConnectionAdapters::SqlTypeMetadata:0x00007fe001502ad8 @limit=8, @precision=nil, @scale=nil, @sql_type="bigint", @type=:integer>

So this check:

Does not seem to work.

Thanks!

Auto-corrections

Hey there 👋

I just dropped this wonderful gem into the project that I'm working on, and we have quite a few issues that need to be addressed.

I was wondering if we should have an --auto-correct option, similar to the rubocop's one.

database_consistency --auto-correct # auto-correct everything
database_consistency --auto-correct ForeignKeyChecker # auto-correct specific check
database_consistency --auto-correct ForeignKeyChecker app/models/user.rb # auto-correct specific check for a specific model

Auto-correction in this case is basically the creation of migration files.

What do you folks think?

I'm happy to contribute if it might be useful to someone else.

Checks has_many, has_and_belongs_to_many wrongly

First of all thank you for the amazing tool.

I have a model like;

class Listing < ApplicationRecord
  has_many :listing_items
  has_many :locations
end

and also I have a model,

class FinanceInfo < ApplicationRecord
  has_and_belongs_to_many :payment_methods
end

When I check it shows;

fail Listing listing_items model should have proper foreign key in the database
fail Listing locations model should have proper foreign key in the database
fail FinanceInfo payment_methods model should have proper foreign key in the database 

In my case ListingItem and Location models have FKs for Listing and join table for PaymentMethod also has a FK for FinanceInfo.

I believe this checks should be working only belongs_to relationships but it shows for has_many and has_and_belongs_to_many relationships also.

Thank you.

display check_name for errors

I know setting DEBUG displays check names, but it would be nice if I could see only errors along with the check name. One thing I'm trying to do is selectively disable the checkers that are failing and gradually re-enable them as we correct issues in our schema. It's a little challenging to tell which checker is failing, though, so it's hard to know which one to disable.

What's next?

Hi guys, thank you for using this gem. I hope it helps you 👍

The purpose of this topic is to discuss what should be added next?

Possible features (random order):

  • more detailed output in DEBUG mode
  • generate migrations
  • provide support for different ORMs
  • accept list of files as arguments to check only them
  • support through associations for MissingIndexChecker
  • distinguish between hot/cold issues (i.e. many associations points on FK without index)

Any requests are welcome to be discussed!

Install success despite using Invalid Ruby 2.3.7 Version

Sorry for the telegraphic style, following guess was the best way to be clear.

When we :

run bundle exec database_consistency on ruby 2.3.7

We got : an Error

Did you mean? match

Because

match? have been introduce in 2.4.0

I was expecting :

An error at install time . As this version is not compatible and Ruby 2.3.7, is not supported anymore.

Here the backtrace :

Did you mean?  match
  /Users/edouardetancelin/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/database_consistency-0.7.3/lib/database_consistency/configuration.rb:20:in `debug?'
  /Users/edouardetancelin/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/database_consistency-0.7.3/lib/database_consistency/writers/base_writer.rb:15:in `write?'
  /Users/edouardetancelin/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/database_consistency-0.7.3/lib/database_consistency/writers/simple_writer.rb:17:in `block in write'
  /Users/edouardetancelin/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/database_consistency-0.7.3/lib/database_consistency/writers/simple_writer.rb:16:in `each'
  /Users/edouardetancelin/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/database_consistency-0.7.3/lib/database_consistency/writers/simple_writer.rb:16:in `write'
  /Users/edouardetancelin/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/database_consistency-0.7.3/lib/database_consistency/writers/base_writer.rb:19:in `write'
  /Users/edouardetancelin/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/database_consistency-0.7.3/lib/database_consistency.rb:36:in `run'
  /Users/edouardetancelin/.rbenv/versions/2.3.7/lib/ruby/gems/2.3.0/gems/database_consistency-0.7.3/bin/database_consistency:26:in `<top (required)>'
  /Users/edouardetancelin/.rbenv/versions/2.3.7/bin/database_consistency:22:in `load'
  /Users/edouardetancelin/.rbenv/versions/2.3.7/bin/database_consistency:22:in `<top (required)>'

Add `All` option

so I can do:

All:
  enabled: false

RedundantIndexChecker:
  enabled: true

UniqueIndexChecker does not infer association key from association

In the following code, Rails can correctly infer that validates :category, uniqueness: { scope: :post } refers to the unique index_categorisations_on_category_id_and_post_id but the UniqueIndexChecker doesn't do that inference correctly.

class Categorisation < ActiveRecord::Base 
  belongs_to :category
  belongs_to :post

  # Rails correctly infers `category_id` and `post_id` here but UniqueIndexChecker doesn't and so fails
  validates :category, uniqueness: { scope: :post }
end

I tried to follow the Rails source code for the UniquenessValidator to see how UniqueIndexChecker can be adapted to infer the key too, but I got stuck. Any pointers?

ForeignKeyTypeChecker duplicates

ForeignKeyTypeChecker seems to report the same problem twice (or more for e.g. polymorphic associations).

  1. Duplicate
  create_table "reports", force: :cascade do |t|
    # ...
  end

  create_table "lines", id: :serial, force: :cascade do |t|
    t.integer "report_id"
    # ...
  end

  add_foreign_key "lines", "reports"
class Line < ApplicationRecord
  belongs_to :report, optional: true
  # ...
end

class Report < ApplicationRecord
  has_many :lines, dependent: :destroy
  # ...
end
ForeignKeyTypeChecker fail Line report foreign key (report_id) with type (integer) doesn't cover primary key (id) with type (bigint)
ForeignKeyTypeChecker fail Report lines foreign key (report_id) with type (integer) doesn't cover primary key (id) with type (bigint)
  1. Multiplicate (for a polymorphic association, paper_trail)
  create_table "versions", id: :serial, force: :cascade do |t| # PaperTrail gem
    t.string "item_type", null: false
    t.integer "item_id", null: false
    # ...
  end
# Not much to show here, as it's all just from PaperTrail
class Foo < ApplicationRecord
  has_paper_trail
  # ...
end

class Bar < ApplicationRecord
  has_paper_trail
  # ...
end

class Baz < ApplicationRecord
  has_paper_trail
  # ...
end
ForeignKeyTypeChecker fail Foo versions foreign key (item_id) with type (integer) doesn't cover primary key (id) with type (bigint)
ForeignKeyTypeChecker fail Bar versions foreign key (item_id) with type (integer) doesn't cover primary key (id) with type (bigint)
ForeignKeyTypeChecker fail Baz versions foreign key (item_id) with type (integer) doesn't cover primary key (id) with type (bigint)
# ... more of them in my app, one per model with `has_paper_trail`

Reserved word and uniqueness validation

First of all, I want to say thank you for this gem!!!

We found an issue where the column name is equal to a reserved word and we have to add an index to make it unique.

RSpec.describe DatabaseConsistency::Checkers::MissingUniqueIndexChecker do
  subject(:checker) { described_class.new(model, attribute, validator) }

  let(:model) { klass }
  let(:attribute) { :from }
  let(:validator) { klass.validators.first }

  context 'with postgresql database' do
    include_context 'postgresql database context'

    context 'when uniqueness validation has case sensitive option turned off' do
      context 'when the column name is equal to a reserved word' do
        let(:klass) { define_class { |klass| klass.validates :from, uniqueness: { case_sensitive: false } } }

        before do
          define_database_with_entity do |table|
            table.string :from
            table.index "lower('from')", unique: true
          end
        end

        specify do
          expect(checker.report).to have_attributes(
            checker_name: 'MissingUniqueIndexChecker',
            table_or_model_name: klass.name,
            column_or_attribute_name: 'lower(from)',
            status: :ok,
            message: nil
          )
        end
      end
    end
  end
end

It looks like the problem occurs during the following comparison:

extract_index_columns(index.columns).sort == sorted_index_columns

which equals

["lower('from'::text)"] == ["lower(from)"]

Doesn't appear to work? False negatives.

It appears that all the validators are failing, even a very simple null: false column in my database is appearing as nullable and getting flagged by database_consistency.

I am using Rails v6.0.0.rc2 if it matters, along with the mysql2 v0.4.4 gem.

Here is an example:

Migration:

class DeviseTokenAuthCreateUsers < ActiveRecord::Migration[6.0]
  def change
    create_table(:users, id: false) do |t|
      t.string :id, limit: 36, primary_key: true, null: false
      ## Required
      t.string :uid, null: false, default: ''
      ....
   end
end 

Schema:

  create_table "users", id: :string, limit: 36, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t|
    t.string "uid", default: "", null: false
   ...
  end

And when I run the database consistency rake task, I get this:

fail User uid column is required but there is possible null value insert

foreign_key_type_checker error

Hello, after updating to 0.8.6 I got the following error:

Hey, some of checks fail with an error, please open an issue on github at https://github.com/djezzzl/database_consistency. Attach the created file: database_consistency_2020_09_23_17_30_48

The content of file is:

<===begin===> �[1mTraceback�[m (most recent call last): 24: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/bin/ruby_executable_hooks:24:in

'
23: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/bin/ruby_executable_hooks:24:in eval' 22: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/bin/database_consistency:23:in '
21: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/bin/database_consistency:23:in load' 20: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/bin/database_consistency:44:in <top (required)>'
19: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency.rb:46:in run' 18: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/base_processor.rb:12:in reports'
17: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/base_processor.rb:12:in flat_map' 16: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/base_processor.rb:12:in each'
15: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/base_processor.rb:13:in block in reports' 14: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/base_processor.rb:28:in reports'
13: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/associations_processor.rb:15:in check' 12: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/associations_processor.rb:15:in flat_map'
11: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/associations_processor.rb:15:in each' 10: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/associations_processor.rb:18:in block in check'
9: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/associations_processor.rb:18:in flat_map' 8: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/associations_processor.rb:18:in each'
7: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/associations_processor.rb:19:in block (2 levels) in check' 6: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/associations_processor.rb:19:in map'
5: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/associations_processor.rb:21:in block (3 levels) in check' 4: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/checkers/base_checker.rb:30:in report_if_enabled?'
3: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/checkers/base_checker.rb:23:in report' 2: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:36:in check'
1: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:96:in converted_type' /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:89:in type': �[1mundefined method sql_type' for nil:NilClass (�[1;4mNoMethodError�[m�[1m)�[m <===end===> <===begin===> �[1mTraceback�[m (most recent call last): 24: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/bin/ruby_executable_hooks:24:in '
23: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/bin/ruby_executable_hooks:24:in eval' 22: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/bin/database_consistency:23:in '
21: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/bin/database_consistency:23:in load' 20: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/bin/database_consistency:44:in <top (required)>'
19: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency.rb:46:in run' 18: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/base_processor.rb:12:in reports'
17: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/base_processor.rb:12:in flat_map' 16: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/base_processor.rb:12:in each'
15: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/base_processor.rb:13:in block in reports' 14: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/base_processor.rb:28:in reports'
13: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/associations_processor.rb:15:in check' 12: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/associations_processor.rb:15:in flat_map'
11: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/associations_processor.rb:15:in each' 10: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/associations_processor.rb:18:in block in check'
9: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/associations_processor.rb:18:in flat_map' 8: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/associations_processor.rb:18:in each'
7: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/associations_processor.rb:19:in block (2 levels) in check' 6: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/associations_processor.rb:19:in map'
5: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/processors/associations_processor.rb:21:in block (3 levels) in check' 4: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/checkers/base_checker.rb:30:in report_if_enabled?'
3: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/checkers/base_checker.rb:23:in report' 2: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:36:in check'
1: from /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:96:in converted_type' /Users/user/.rvm/gems/ruby-2.7.1@my_project/gems/database_consistency-0.8.6/lib/database_consistency/checkers/association_checkers/foreign_key_type_checker.rb:89:in type': �[1mundefined method `sql_type' for nil:NilClass (�[1;4mNoMethodError�[m�[1m)�[m
<===end===>

`

Seems that it is possible to have nil in foreign_key_type_checker.rb:89 type method. Please let me know if you need more context for fixing it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.