mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
98 lines
3.5 KiB
Ruby
98 lines
3.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'spec_helper'
|
|
|
|
RSpec.describe "Database" do
|
|
excluded_models = ["Gateway", "PayPalExpress", "Bogus", "BogusSimple"].freeze
|
|
|
|
it "should have foreign keys for models with a belongs_to relationship" do
|
|
pending "Consider adding foreign keys"
|
|
Rails.application.eager_load!
|
|
model_classes = filter_model_classes
|
|
|
|
migrations = generate_migrations(model_classes)
|
|
|
|
expect(migrations.length).to eq(0)
|
|
end
|
|
|
|
def filter_model_classes
|
|
Dir.glob(Rails.root.join('app/models/**/*.rb').to_s)
|
|
.map { |file| File.basename(file, '.rb').camelize }
|
|
.reject { |model| excluded_models.include?(model) }
|
|
end
|
|
|
|
def generate_migrations(model_classes)
|
|
migrations = []
|
|
previous_models = {}
|
|
|
|
ActiveRecord::Base.descendants.each do |model_class|
|
|
next unless model_classes.include?(model_class.name.demodulize)
|
|
|
|
model_class.reflect_on_all_associations(:belongs_to).each do |association|
|
|
migration = process_association(model_class, association, previous_models)
|
|
migrations << migration unless migration.nil?
|
|
end
|
|
end
|
|
|
|
if migrations
|
|
puts "Foreign key(s) appear to be absent from the database. " \
|
|
"You can add it/them using the following migration(s):"
|
|
puts migrations.join("\n")
|
|
puts "To disable this warning, add the class name(s) of the model(s) to EXCLUDED_MODELS " \
|
|
"in /spec/models/missing_foreign_keys_spec.rb"
|
|
end
|
|
|
|
migrations
|
|
end
|
|
|
|
def process_association(model_class, association, previous_models)
|
|
return if association.options[:polymorphic]
|
|
|
|
foreign_key_table_name = determine_foreign_key_table_name(model_class, association)
|
|
foreign_key_column = "#{association.options[:foreign_key] || association.name}_id"
|
|
|
|
# Filter out duplicate migrations
|
|
return if duplicate_migration?(model_class, foreign_key_table_name, previous_models)
|
|
|
|
previous_models[model_class.table_name] ||= []
|
|
previous_models[model_class.table_name] << foreign_key_table_name
|
|
|
|
generate_migration(model_class, association, foreign_key_table_name, foreign_key_column)
|
|
end
|
|
|
|
def determine_foreign_key_table_name(model_class, association)
|
|
if association.options[:class_name]
|
|
class_name = association.options[:class_name].underscore.parameterize
|
|
foreign_key_table_name = class_name.tableize
|
|
else
|
|
foreign_key_table_name = association.class_name.underscore.parameterize.tableize
|
|
namespace = model_class.name.deconstantize
|
|
|
|
unless association.class_name.deconstantize == namespace || namespace == "" ||
|
|
ActiveRecord::Base.connection.table_exists?(foreign_key_table_name)
|
|
foreign_key_table_name = "#{namespace.underscore}_#{foreign_key_table_name}"
|
|
end
|
|
end
|
|
|
|
foreign_key_table_name
|
|
end
|
|
|
|
def generate_migration(model_class, _association, foreign_key_table_name, foreign_key_column)
|
|
migration_name = "add_foreign_key_to_#{model_class.table_name}_#{foreign_key_table_name}"
|
|
migration_class_name = migration_name.camelize
|
|
|
|
<<~MIGRATION
|
|
class #{migration_class_name} < ActiveRecord::Migration[6.0]
|
|
def change
|
|
add_foreign_key :#{model_class.table_name}, :#{foreign_key_table_name}, column: :#{foreign_key_column}
|
|
end
|
|
end
|
|
MIGRATION
|
|
end
|
|
|
|
def duplicate_migration?(model_class, foreign_key_table_name, previous_models)
|
|
model_class.connection.foreign_key_exists?(model_class.table_name, foreign_key_table_name) ||
|
|
previous_models[model_class.table_name]&.include?(foreign_key_table_name)
|
|
end
|
|
end
|