I’m trying to create a foreign key relationship with the Topics table.
The problem is it is failing in github workflow test environment during tests for the strangest reason, it is trying to access a field from the parent table that no longer exists and was removed in a core migration years ago!
The error is PG::UndefinedColumn: ERROR: column topics.off_topic_count does not exist
I’m not in any way referencing this old parent table field explicitly … it seems to be generating the SQL itself … but inappropriately for the current definition of things.
== 20231119010101 CreateLocationsTopicTable: migrating ========================rake aborted!
[12035](https://github.com/paviliondev/discourse-locations/actions/runs/7039607316/job/19158951878?pr=103#step:19:12036)StandardError: An error has occurred, this and all later migrations canceled: (StandardError)
[12036](https://github.com/paviliondev/discourse-locations/actions/runs/7039607316/job/19158951878?pr=103#step:19:12037)
[12037](https://github.com/paviliondev/discourse-locations/actions/runs/7039607316/job/19158951878?pr=103#step:19:12038)PG::UndefinedColumn: ERROR: column topics.off_topic_count does not exist
[12038](https://github.com/paviliondev/discourse-locations/actions/runs/7039607316/job/19158951878?pr=103#step:19:12039)LINE 1: ...cs"."deleted_at", "topics"."highest_post_number", "topics"."...
The table def is really simple:
class CreateLocationsTopicTable < ActiveRecord::Migration[7.0]
def change
create_table :locations_topic do |t|
t.references :topic, foreign_key: true
t.float :latitude, null: false
SNIP
The even weirder part is that this migration works in Production!
Offenses:
db/migrate/20231119010101_create_locations_topic_table.rb:6:7: C: Discourse/NoAddReferenceOrAliasesActiveRecordMigration: AR methods add_reference, add_belongs_to, t.references, and t.belongs_to are
high-risk for large tables and have too many background magic operations.
Instead, write a disable_ddl_transactions! migration and write custom SQL to
add the new column and CREATE INDEX CONCURRENTLY. Use the IF NOT EXISTS clause
to make the migration re-runnable if it fails partway through.
t.references :topic, foreign_key: true
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The rubocop advice is good, but I don’t think it’s the cause of this error. (the ‘risk’ it mentions refers to locks on high-traffic tables which would affect production traffic. So not something which would cause errors in a test environment)
You can probably reproduce the same error locally by doing RAILS_ENV=test bin/rake db:drop db:create db:migrate (i.e. migrating a database totally from scratch, with the locations plugin enabled)
I suspect the issue is that you’re invoking Rake tasks inside a migration. In core we generally avoid running any kind of application code in migrations because of the weird side effects that can happen. Best to stick to raw SQL.
In this case, my assumption is that the ActiveRecord schema cache is being populated early in the migrations (when topics.off_topic_count still exists). Then, when your rake task runs, it’s running with an old schema cache and so ActiveRecord tries to load columns which no longer exist.
You can probably mitigate by adding ActiveRecord::Base.clear_cache! before invoking the rake tasks… but don’t take that as a recommendation . Best thing would be to avoid invoking the rake tasks altogether. If you need to do manipulate something in the database, use raw SQL within the migration.