Rails 新迁移不更新旧数据

问题描述 投票:0回答:2

我有一个名为 Article 的模型。该模型具有称为“持续时间”的属性,它是一个字符串。持续时间可以是上午、下午、傍晚和夜间。

例如,文章对象如下所示:

#<Article id: 1, created_at: "2015-09-22 08:00:08", updated_at: "2015-09-22 08:00:08", duration: "morning">

由于持续时间具有类似的属性,因此我创建了一个名为持续时间的基类,并创建了继承类作为上午、下午、晚上和晚上。

在一段时间内可以有很多文章。但一篇文章只能有一个持续时间。所以,我有

has_many
belongs_to
关联:

app/model/duration.rb
class Duration < ActiveRecord::Base
  has_many :articles
end

app/model/article.rb
class Article < ActiveRecord::Base
  belongs_to :duration
end

其他继承类有:

app/model/duration/morning.rb
class Morning < Duration
end

等等

afternoon.rb
evening.rb
night.rb

我已经迁移到创建持续时间表。要将字段

type
添加到持续时间,我有一个名为
add_type_to_duration.rb

的迁移
AddTypeToDuration < ActiveRecord::Migration
  def change
    add_column :durations, :type, :string
  end 
end

我有另一个名为

add_duration_ref_to_articles.rb
的迁移文件来添加参考

class AddDurationRefToArticles < ActiveRecord::Migration
  def change
    add_reference :articles, :duration, index:true
  end
end

我有另一个迁移来在 add_initial_durations.rb 中创建新的持续时间

class AddInitialDurations < ActiveRecord::Migration
  def change
    Morning.create
    Afternoon.create
    Evening.create
    Night.create 
  end
end

现在我想更新旧数据以适应新的迁移。所以,我有另一个名为

update_articles_to_have_duration.rb

的迁移
class UpdateArticlesToHaveDuration < ActiveRecord::Migration
  def change
    morning = Duration.find_by_type("Morning")
    Article.where(duration: "morning").find_each do |article|
      article.update!(duration_id: morning.id)
    end
  end
end

现在,当我运行迁移时,所有具有

duration = morning
的文章,现在都具有
duration_id = nil
。但是,当我使用
rake db:migrate:redo step:1
再次运行上次迁移时,文章具有正确的 period_id。我认为不知何故迁移没有正常运行。但是,我在运行它们时没有收到任何错误。谁能告诉我我在这里做错了什么吗?

感谢您的帮助。

database ruby-on-rails-4 sqlite migration sti
2个回答
2
投票

正如您所说,第二次运行迁移时

duration_id
设置正确,第一次运行时不起作用的唯一原因可能是迁移没有像您所显示的那样按顺序运行。

迁移文件上有 时间戳,当您执行

rake db:migrate
时,它们会先运行最旧的。 查看迁移文件的时间戳,以确保它们按照您想要的顺序排列。

❯ rake db:migrate:status                                                                                                 

database: ~/blog/db/development.sqlite3

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20150907015616  Create articles
  down    20150907031746  Create comments
  down    20150909034614  Devise create users

您可以使用上面的命令查看迁移 Id 并将其复制以依次运行迁移,以使用以下命令验证我的假设:

❯ bin/rake db:migrate VERSION=20150907015616 VERSION=20150907031746 VERSION=20150909034614

如果迁移文件不遵循时间戳的时间顺序,则必须重新排序(最好删除并重新创建)迁移文件或转置其内容。


0
投票

我遇到了同样的问题并使用

MyModel.reset_column_information

解决了它
class UpdateArticlesToHaveDuration < ActiveRecord::Migration
  def change
    Article.reset_column_information

    morning = Duration.find_by_type("Morning")
    Article.where(duration: "morning").find_each do |article|
      article.update!(duration_id: morning.id)
    end
  end
end

它会重置有关列的所有缓存信息,这将导致它们在下一个请求时重新加载。

此方法最常见的使用模式可能是在迁移中,当创建表后您想用一些默认值填充它时

更多详情,您可以参考文档

© www.soinside.com 2019 - 2024. All rights reserved.