Estoy intentando crear una relación de clave externa con la tabla Topics.
El problema es que falla en el entorno de prueba del flujo de trabajo de GitHub durante las pruebas por una razón extraña: está intentando acceder a un campo de la tabla principal que ya no existe y que se eliminó en una migración principal hace años.
El error es PG::UndefinedColumn: ERROR: column topics.off_topic_count does not exist
No estoy haciendo referencia explícita a este antiguo campo de la tabla principal… parece que está generando el SQL por sí mismo… pero de forma inapropiada para la definición actual de las cosas.
== 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"...
La definición de la tabla es muy 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
Lo más extraño es que esta migración ¡funciona en Producción!
Ofensas:
db/migrate/20231119010101_create_locations_topic_table.rb:6:7: C: Discourse/NoAddReferenceOrAliasesActiveRecordMigration: Los métodos AR add_reference, add_belongs_to, t.references y t.belongs_to son de alto riesgo para tablas grandes y tienen demasiadas operaciones mágicas en segundo plano.
En su lugar, escriba una migración disable_ddl_transactions! y escriba SQL personalizado para agregar la nueva columna y CREATE INDEX CONCURRENTLY. Utilice la cláusula IF NOT EXISTS para que la migración se pueda volver a ejecutar si falla a mitad de camino.
t.references :topic, foreign_key: true
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
El consejo de Rubocop es bueno, pero no creo que sea la causa de este error. (el ‘riesgo’ que menciona se refiere a bloqueos en tablas de alto tráfico que afectarían el tráfico de producción. Así que no es algo que cause errores en un entorno de prueba)
Probablemente puedas reproducir el mismo error localmente ejecutando RAILS_ENV=test bin/rake db:drop db:create db:migrate (es decir, migrando una base de datos totalmente desde cero, con el plugin de ubicaciones habilitado)
Sospecho que el problema es que estás invocando tareas Rake dentro de una migración. En el núcleo, generalmente evitamos ejecutar cualquier tipo de código de aplicación en las migraciones debido a los extraños efectos secundarios que pueden ocurrir. Es mejor ceñirse a SQL puro.
En este caso, mi suposición es que la caché del esquema de ActiveRecord se está poblando al principio de las migraciones (cuando topics.off_topic_count todavía existe). Luego, cuando tu tarea Rake se ejecuta, lo hace con una caché de esquema antigua y, por lo tanto, ActiveRecord intenta cargar columnas que ya no existen.
Probablemente puedas mitigar esto agregando ActiveRecord::Base.clear_cache! antes de invocar las tareas Rake… pero no lo tomes como una recomendación . Lo mejor sería evitar invocar las tareas Rake por completo. Si necesitas manipular algo en la base de datos, usa SQL puro dentro de la migración.