Rails5部署Heroku遇PG::UndefinedTable错误:stocks表不存在
看起来你遇到的核心问题是Heroku上的PostgreSQL数据库中没有创建stocks表,或者在资产预编译阶段提前触发了数据库查询导致报错。下面是一步步的排查和解决方法:
1. 确认Heroku是否执行了创建stocks表的迁移
本地的schema已经包含stocks表,但Heroku的数据库可能没同步。你需要手动在Heroku上运行迁移:
- 在终端执行:
heroku run rails db:migrate - 迁移完成后重启应用,确保更改生效:
heroku restart - 可以检查迁移状态,确认
20180112181551_create_stock这个迁移是否已执行:
如果这个迁移显示为heroku run rails db:migrate:statusdown,说明没执行成功,你可以尝试重新跑迁移,或者查看Heroku日志找迁移失败的原因。
2. 解决资产预编译时的数据库查询问题
从你的部署日志可以看到,报错发生在资产预编译阶段(Writing assets的时候紧接着执行了Stock Load查询)。这是因为你的视图代码里直接调用了Stock.all.each,而Rails在预编译资产时会渲染视图,触发了这个数据库查询——但此时Heroku的数据库还没完成迁移(Heroku的部署流程是先预编译资产,再执行迁移),所以表不存在。
解决这个问题有两种常用方法:
方法一:将数据库查询移到控制器中
修改对应页面的控制器,在目标action里获取stocks数据:
# 比如对应的Orders控制器或其他相关控制器 def new @stocks = Stock.all end
然后修改视图代码,使用控制器传递的实例变量:
<select name="order[order_placed][][itemname]" id="order_place_id" class="form-control" style="width: 300px"> <option value=""></option> <% @stocks.each do |stock| %> <option value="<%= stock.item_name %>"> <%= stock.item_name %> </option> <% end %> </select>
这样预编译资产时,因为控制器逻辑不会被执行,就不会触发数据库查询。
方法二:禁用预编译时的初始化
在config/application.rb中添加以下配置,阻止Rails在预编译资产时初始化整个应用(包括数据库连接):
config.assets.initialize_on_precompile = false
这个配置在Rails 5中默认可能已经是false,但如果你的项目有特殊配置被修改过,手动设置可以避免预编译时的数据库查询。
3. 重置Heroku数据库(如果迁移始终失败)
如果上面的方法都没用,你可以尝试重置Heroku的数据库,重新执行所有迁移:
# 重置数据库(会清空所有数据,谨慎操作) heroku pg:reset DATABASE # 重新运行所有迁移 heroku run rails db:migrate # 重启应用 heroku restart
4. 检查迁移文件的正确性
确认你的20180112181551_create_stock.rb迁移文件没有语法错误,且正确创建了复数的stocks表(符合Rails的命名约定)。正确的迁移文件应该类似:
class CreateStock < ActiveRecord::Migration[5.1] def change create_table :stocks do |t| t.string :item_name t.string :item_id t.float :unit_price t.float :tax t.float :discount t.timestamps end end end
按照这些步骤操作后,应该能解决PG::UndefinedTable的错误。
内容的提问来源于stack exchange,提问作者Abdul Mukheem Shaik

