Estou tentando criar um relacionamento de chave estrangeira com a tabela Topics.
O problema é que está falhando no ambiente de teste do fluxo de trabalho do GitHub durante os testes pela razão mais estranha: ele está tentando acessar um campo da tabela pai que não existe mais e foi removido em uma migração principal anos atrás!
O erro é PG::UndefinedColumn: ERROR: column topics.off_topic_count does not exist
Não estou de forma alguma referenciando explicitamente esse campo antigo da tabela pai… parece que ele está gerando o SQL por conta própria… mas de forma inadequada para a definição atual das coisas.
== 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"...
A definição da tabela é muito simples:
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
A parte ainda mais estranha é que essa migração funciona em Produção!
Offenses:
db/migrate/20231119010101_create_locations_topic_table.rb:6:7: C: Discourse/NoAddReferenceOrAliasesActiveRecordMigration: Métodos AR add_reference, add_belongs_to, t.references e t.belongs_to são de alto risco para tabelas grandes e têm muitas operações mágicas em segundo plano.
Em vez disso, escreva uma migração disable_ddl_transactions! e escreva SQL personalizado para adicionar a nova coluna e CREATE INDEX CONCURRENTLY. Use a cláusula IF NOT EXISTS para tornar a migração reexecutável se ela falhar parcialmente.
t.references :topic, foreign_key: true
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
O conselho do Rubocop é bom, mas não acho que seja a causa deste erro. (o ‘risco’ que ele menciona se refere a bloqueios em tabelas de alto tráfego que afetariam o tráfego de produção. Portanto, não é algo que causaria erros em um ambiente de teste)
Você provavelmente pode reproduzir o mesmo erro localmente executando RAILS_ENV=test bin/rake db:drop db:create db:migrate (ou seja, migrando um banco de dados totalmente do zero, com o plugin de locais ativado)
Suspeito que o problema seja que você está invocando tarefas Rake dentro de uma migração. No core, geralmente evitamos executar qualquer tipo de código de aplicativo em migrações por causa dos efeitos colaterais estranhos que podem acontecer. É melhor usar SQL puro.
Neste caso, minha suposição é que o cache de esquema do ActiveRecord está sendo preenchido no início das migrações (quando topics.off_topic_count ainda existe). Então, quando sua tarefa rake é executada, ela roda com um cache de esquema antigo e, portanto, o ActiveRecord tenta carregar colunas que não existem mais.
Você provavelmente pode mitigar isso adicionando ActiveRecord::Base.clear_cache! antes de invocar as tarefas rake… mas não tome isso como uma recomendação . A melhor coisa seria evitar invocar as tarefas rake completamente. Se você precisar manipular algo no banco de dados, use SQL puro dentro da migração.