为什么迁移在生产中失败但在开发中没有?

时间:2012-07-18 21:37:11

标签: ruby-on-rails ruby-on-rails-3.1 migration

迁移在生产中失败,但在开发过程中按预期运行。

...                                                               # everything to
20120709174326_add_subject_to_campaigns.rb                        # here runs fine.
20120711001125_set_default_value_for_publishable_in_newsletter.rb # <- this fails.
20120711010818_set_default_value_for_publishable_in_contents.rb
20120711010855_set_default_value_for_published_in_editions.rb
20120711191427_add_newsletter_date_to_newsletters.rb
20120711194230_rename_cm_campaign_sent_at_in_campaigns.rb

迁移错误如下所示:

-bash> heroku run rake db:migrate --remote staging
Running rake db:migrate attached to terminal... up, run.1
==  SetDefaultValueForPublishableInNewsletter: migrating ======================
-- change_column(:newsletters, :publishable, :boolean, {:default=>false})
   -> 0.1554s
rake aborted!
An error has occurred, this and all later migrations canceled:

undefined method `newsletter_date' for #<Newsletter:0x00000005961bd0>

问题是,newsletter_date直到后来都没有添加,所以为什么这么快就失败/提到它?它在开发中运行得非常好。

1 个答案:

答案 0 :(得分:1)

事实证明失败的迁移(20120711001125_set_default_value_for_publishable_in_newsletter.rb)......

def up
  change_column :newsletters, :publishable, :boolean, default: false
  Newsletter.scoped.where('publishable is NULL').each do |n|
    n.publishable = false
    n.save
  end
end

... uses the model Newsletter,并在保存之前运行验证(特别是presence上的newsletter_date验证)...

validates :newsletter_date, presence: true

...但newsletter_date尚不存在,因为它(newsletter_date列)直到稍后才会添加(20120711191427_add_newsletter_date_to_newsletters.rb - 上面列表中的倒数第二次迁移):

class AddNewsletterDateToNewsletters < ActiveRecord::Migration
  def change
    add_column :newsletters, :newsletter_date, :date
  end
end

解决方案是:(1)在开发中,回滚迁移到失败之前的迁移; (2)重命名添加列的迁移,将其时间戳更改为失败迁移之前; (3)运行迁移; (4)更新 git; (5)推送到Heroku; (6)在生产中,运行迁移; (7)重启 Heroku进程。

bundle exec rake db:rollback # five times in this case
mv db/migrate/20120711191427_add_newsletter_date_to_newsletters.rb db/migrate/20120711001025_add_newsletter_date_to_newsletters.rb
bundle exec rake db:migrate
git add db/migrate/20120711001025_add_newsletter_date_to_newsletters.rb
git rm db/migrate/20120711191427_add_newsletter_date_to_newsletters.rb
git commit -m "changed migration timestamp to fix migration order issue"
git push staging master
heroku run rake db:migrate --remote staging
heroku restart --remote staging

它在开发中工作的原因是因为在publishable表中设置newsletters列的默认值的迁移运行时,newsletter_date列和模型验证确实发生了尚未存在,所以这不是问题。当它全部投入生产时,最近的代码使newsletter_date方法和相关验证成为现实,但由于迁移按时间戳的顺序在现有代码上运行,因此可能存在比数据库准备好的更新的代码