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

如何调整Elixir应用适配Heroku上heroku_ext schema的PostgreSQL扩展

解决Heroku Review App中PostgreSQL扩展架构错误的Elixir调整方案

错误背景

创建Heroku Review App时遇到以下数据库错误:

psql:/priv/repo/structure.sql:25: ERROR:  Extensions can only be created on heroku_ext schema
CONTEXT:  PL/pgSQL function inline_code_block line 7 at RAISE

该问题因Heroku 2022年8月1日起实施的PostgreSQL扩展架构规则变更导致——所有扩展必须创建在heroku_ext schema下。

分场景解决方案

1. 在迁移中创建扩展

修改Ecto迁移文件,指定扩展创建到heroku_ext schema,并兼容本地开发环境:

defmodule MyApp.Repo.Migrations.AddUnaccentExtension do
  use Ecto.Migration

  def up do
    db_name = Application.get_env(:my_app, MyApp.Repo)[:database]

    if System.get_env("HEROKU") do
      # Heroku环境:指定schema创建扩展,并更新数据库搜索路径
      execute "CREATE EXTENSION IF NOT EXISTS unaccent WITH SCHEMA heroku_ext;"
      execute "ALTER DATABASE #{db_name} SET search_path TO public, heroku_ext;"
    else
      # 本地环境:默认schema创建扩展
      execute "CREATE EXTENSION IF NOT EXISTS unaccent;"
    end
  end

  def down do
    db_name = Application.get_env(:my_app, MyApp.Repo)[:database]

    if System.get_env("HEROKU") do
      execute "DROP EXTENSION IF EXISTS unaccent;"
      execute "ALTER DATABASE #{db_name} SET search_path TO public;"
    else
      execute "DROP EXTENSION IF EXISTS unaccent;"
    end
  end
end
  • 部署到Heroku时,需在控制台添加HEROKU环境变量(值设为true即可)。

2. 在priv/repo/structure.sql中创建扩展用于mix ecto.load

修改structure.sql中的扩展创建逻辑,自动适配本地/Heroku环境:

-- 自动判断环境,创建对应schema的扩展
SELECT CASE 
  WHEN EXISTS (SELECT 1 FROM pg_namespace WHERE nspname = 'heroku_ext') THEN
    'CREATE EXTENSION IF NOT EXISTS unaccent WITH SCHEMA heroku_ext;'
  ELSE
    'CREATE EXTENSION IF NOT EXISTS unaccent;'
END \gexec

-- 全局设置搜索路径(自动适配环境)
SELECT CASE 
  WHEN EXISTS (SELECT 1 FROM pg_namespace WHERE nspname = 'heroku_ext') THEN
    format('ALTER DATABASE %I SET search_path TO public, heroku_ext;', current_database())
  ELSE
    format('ALTER DATABASE %I SET search_path TO public;', current_database())
END \gexec
  • 执行mix ecto.load时,该逻辑会自动匹配当前环境,无需手动切换配置。

3. 代码中使用扩展函数(如UNACCENT())

有两种方式确保函数调用正常:

方式一:设置连接级搜索路径

在生产环境配置中,为Repo添加search_path参数,让所有数据库连接自动包含heroku_ext:

# config/prod.exs
config :my_app, MyApp.Repo,
  url: System.get_env("DATABASE_URL"),
  pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
  parameters: [search_path: "public, heroku_ext"]

设置后,代码中可直接调用函数,无需添加schema前缀:

from u in User,
  where: fragment("unaccent(?) ILIKE unaccent(?)", u.name, ^search_term)

方式二:手动指定schema前缀

如果不想修改全局搜索路径,可在查询中显式指定heroku_ext schema:

from u in User,
  where: fragment("heroku_ext.unaccent(?) ILIKE heroku_ext.unaccent(?)", u.name, ^search_term)

内容的提问来源于stack exchange,提问作者Szymon Jeż

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 20:27:30