You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

部署时ActiveRecord迁移报错:PG::UndefinedTable playlists表不存在

解决Capistrano部署Globalize迁移时的PG::UndefinedTable错误

我之前也碰到过一模一样的问题,本地跑迁移完全正常,一用Capistrano部署就报playlists表不存在。先帮你理清楚问题根源,再给你几个靠谱的解决方案:

问题复盘

你写的迁移代码本身逻辑没问题,本地能正常执行就说明这点:

class AddTranslationsForPlaylistsYoutubesDjSetsAndPodcasts < ActiveRecord::Migration[6.0]
  def change
    reversible do |dir|
      dir.up do
        Djset.create_translation_table!({ title: :string }, { migrate_data: true, remove_source_columns: true })
        Playlist.create_translation_table!({ title: :string }, { migrate_data: true, remove_source_columns: true })
        YouTube.create_translation_table!({ title: :string }, { migrate_data: true, remove_source_columns: true })
        Podcast.create_translation_table!({ title: :string }, { migrate_data: true, remove_source_columns: true })
      end
      dir.down do
        Djset.drop_translation_table! migrate_data: true
        Playlist.drop_translation_table! migrate_data: true
        YouTube.drop_translation_table! migrate_data: true
        Podcast.drop_translation_table! migrate_data: true
      end
    end
  end
end

报错的核心信息是:

PG::UndefinedTable: ERROR: relation "playlists" does not exist
LINE 8: WHERE a.attrelid = '"playlists"'::regclass

问题根源

本地和部署环境的核心差异在于:Capistrano执行迁移时会提前加载整个Rails应用环境,包括所有模型。而Globalize的create_translation_table!方法运行时,会尝试读取原模型表的列信息,此时如果Rails的Schema缓存里没有playlists表的记录(比如部署的是全新环境,或者缓存未及时更新),就会触发这个错误。

本地环境下,你的数据库已经存在playlists表,而且Rails默认不会提前预加载整个应用,所以不会出现这个问题。

解决方案

方案1:改用Globalize的底层迁移方法(最推荐)

不要直接调用模型类的方法,改用Globalize提供的不依赖模型的迁移助手,彻底避免加载模型带来的问题。注意这里要传入数据库的实际表名(比如Djset模型对应dj_sets表,YouTube对应you_tubes表):

class AddTranslationsForPlaylistsYoutubesDjSetsAndPodcasts < ActiveRecord::Migration[6.0]
  def change
    reversible do |dir|
      dir.up do
        create_translation_table :dj_sets, { title: :string }, migrate_data: true, remove_source_columns: true
        create_translation_table :playlists, { title: :string }, migrate_data: true, remove_source_columns: true
        create_translation_table :you_tubes, { title: :string }, migrate_data: true, remove_source_columns: true
        create_translation_table :podcasts, { title: :string }, migrate_data: true, remove_source_columns: true
      end
      dir.down do
        drop_translation_table :dj_sets, migrate_data: true
        drop_translation_table :playlists, migrate_data: true
        drop_translation_table :you_tubes, migrate_data: true
        drop_translation_table :podcasts, migrate_data: true
      end
    end
  end
end

方案2:强制刷新Schema缓存

如果一定要保留调用模型方法的写法,可以在迁移开头强制刷新Rails的Schema缓存,确保能获取到最新的数据库表结构:

class AddTranslationsForPlaylistsYoutubesDjSetsAndPodcasts < ActiveRecord::Migration[6.0]
  def change
    # 清空并重新加载Schema缓存
    ActiveRecord::Base.connection.schema_cache.clear!
    ActiveRecord::Base.connection.schema_cache.reload!

    reversible do |dir|
      dir.up do
        Djset.create_translation_table!({ title: :string }, { migrate_data: true, remove_source_columns: true })
        Playlist.create_translation_table!({ title: :string }, { migrate_data: true, remove_source_columns: true })
        YouTube.create_translation_table!({ title: :string }, { migrate_data: true, remove_source_columns: true })
        Podcast.create_translation_table!({ title: :string }, { migrate_data: true, remove_source_columns: true })
      end
      dir.down do
        Djset.drop_translation_table! migrate_data: true
        Playlist.drop_translation_table! migrate_data: true
        YouTube.drop_translation_table! migrate_data: true
        Podcast.drop_translation_table! migrate_data: true
      end
    end
  end
end

方案3:检查Capistrano迁移配置

如果上面两个方法都不行,可以先排查部署环境的迁移状态:

  1. 在config/deploy.rb中添加一个调试任务:
namespace :deploy do
  desc 'Check database migration status'
  task :check_migrations do
    on roles(:db) do
      within release_path do
        with rails_env: fetch(:rails_env) do
          execute :rake, 'db:migrate:status'
        end
      end
    end
  end
end
  1. 执行cap production deploy:check_migrations,确认创建playlists表的迁移已经被执行。如果没有,说明迁移顺序有问题,需要调整迁移文件的时间戳。

为什么本地没问题?

本地开发环境中,Rails默认不会在执行迁移前预加载整个应用,而且Schema缓存是实时更新的。而Capistrano为了部署效率,会提前加载应用环境,导致模型被提前加载,此时如果Schema缓存没有playlists表的信息,就会触发报错。

内容的提问来源于stack exchange,提问作者Alex Zakruzhetskyi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 19:42:39