为什么这个rails查询在本地工作但在Heroku上失败?

时间:2013-03-14 21:22:31

标签: ruby-on-rails ruby-on-rails-3 heroku rails-migrations

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

@featured_topics = Topic.find_all_by_featured(true)

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

1 个答案:

答案 0 :(得分:4)

这里的问题是一个微妙的问题,只有当您的应用处于生产模式时(即ENV['RAILS_ENV']ENV['RACK_ENV'] = production),这是Heroku的默认配置。

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

要了解在Heroku案件中如何发生这种情况,请考虑以下顺序:

  1. 使用新Topic.find_all_by_featured列引用部署了应用
    1. 应用程序由Heroku
    2. 自动重启
    3. 请求进入您的应用程序,导致类从数据库的当前状态加载到内存中(没有featured列)
  2. 您运行heroku run bundle exec rake db:migrate
    1. Heroku上的数据库使用新的featured
    2. 进行更新
    3. Heroku dyno内存中的模型类重新加载。他们仍然不知道新栏目。
  3. 你点击了你的应用。 Rails抛出错误,因为代码中引用的字段不在其数据库列的列表中(在步骤#1中加载)。
  4. 避免这种情况的正确顺序是为部署和数据库迁移启用维护模式:

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

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