1

我的控制器中有以下方法:

@featured_topics = Topic.find_all_by_featured(true)

它在本地运行良好,但是当我将我的网站上传到 Heroku 时,它失败了,并且我收到了 NoMethodError。“精选”是一个新专栏,但我上传了必要的文件并在 Heroku 上运行了 rake db:migrate。为什么它在 Heroku 上不起作用?该网站的其余部分仍然有效。

4

1 回答 1

4

这里的问题是一个微妙的问题,仅当您的应用程序处于生产模式(即当ENV['RAILS_ENV']ENV['RACK_ENV']=时production)时才会出现,这是 Heroku 上的默认配置。

当 Rails 应用程序处于production模式时,它不会在每个请求上重新加载类定义(就像在development本地运行的模式下一样)。模型类定义的一部分是加载类时从数据库列中获取的属性。因此,如果您在 中加载一个类production,然后更改数据库,加载的类将不知道数据库已更改,您将获得NoMethodError新列的。

要了解您在 Heroku 上的情况如何发生这种情况,请考虑以下顺序:

  1. Topic.find_all_by_featured使用新列引用 部署的应用程序
    1. Heroku 自动重启应用
    2. 一个请求进入您的应用程序,导致类从数据库的当前状态加载到内存中(无featured列)
  2. 你跑heroku run bundle exec rake db:migrate
    1. 您在 Heroku 上的数据库已更新为新featured
    2. Heroku 测功机中已经在内存中的模型类不会重新加载。他们仍然不知道新专栏。
  3. 你点击了你的应用程序。Rails 抛出错误,因为代码中引用的字段不在其数据库列列表中(在步骤 #1 加载)。

避免这种情况的正确顺序是为部署和数据库迁移打开维护模式:

$ heroku maintenance:on
$ git push heroku master
$ heroku run bundle exec rake db:migrate
$ heroku maintenance:off

在部署和迁移时打开维护可确保您的应用程序不会处理任何请求,并且不会加载任何类(具有不正确的列列表)。只有在数据库处于正确状态后,您才允许请求。

于 2013-03-15T14:54:53.563 回答