27

我是一名初级 Rails 开发人员,在工作中我们遇到了以下问题:

只需要为一条记录更新列的值。我们所做的是创建这样的迁移:

class DisableAccessForUser < ActiveRecord::Migration
  def change
    User.where(name: "User").first.update_column(:access, false)
  end
end

迁移仅用于模式更改吗?

您还建议什么其他解决方案?

PS:我只能用代码来改变它。无法访问控制台。

4

7 回答 7

22

简短的版本是,由于迁移仅用于模式更改,因此您不希望使用它们来更改数据库中的实际数据。

主要问题是,如果其他开发人员使用rake db:schema:load或加载数据库结构,您的数据操作迁移可能会被忽略rake db:reset。两者都只是使用schema.rb文件加载结构的最新版本,而不涉及迁移。

正如 Nikita Singh 在评论中指出的那样,我也想说更改行数据的最佳方法是实现一个简单的 rake 任务,该任务可以根据需要运行,与迁移结构无关。或者,对于第一次安装,该seed.rb文件非常适合加载初始系统数据。

希望漫谈有帮助。

更新

在一些“官方”来源中找到了一些文档:

  • Rails 迁移指南 - 在迁移中使用模型。本节描述迁移文件中的数据操作可能会给其他开发人员带来问题的场景。
  • Rails 迁移指南 - 迁移和种子数据。与上面相同的文档,并没有真正解释为什么在迁移中放置种子或数据操作是不好的,只是说将所有这些都放在seed.rd文件中。
  • 这个 SO 答案。这个人基本上和我上面写的一样,除了他们提供了来自Rails 的敏捷 Web 开发(第 3 版)一书的引用,部分由Rails 的创建者David Heinemeier Hansson撰写。我不会复制引用,因为您可以在该帖子中阅读它,但我相信它可以让您更好地了解为什么迁移中的种子或数据操作可能被认为是一种不好的做法。
于 2013-10-28T12:49:03.827 回答
2

迁移适用于架构更改。但是,当您从事许多协作项目时,例如每天从许多开发人员那里提取代码。

您可能会错过一些迁移(值更新迁移..架构更改没有问题)因为迁移取决于时间戳。

所以我们要做的是在单个命名空间中创建一个 rake 任务来更新一些表值(注意它不会覆盖)

并在我们从 Git 更新代码时调用该 NameSpace 中的所有 rake 任务。

于 2013-10-28T13:34:38.723 回答
2

在迁移中使用类进行数据更改是危险的,因为它不是非常适合未来的证明。对类的更改很容易在将来破坏迁移。

例如,假设您要向用户 (sample_group) 添加一个新列,并在对象加载时执行的 Rails 生命周期回调中访问该列(例如 after_initialize)。这将打破这种迁移。如果您没有跳过保存时的回调和验证(通过使用 update_column),那么将来会有更多方法来打破这种迁移。

当我想在迁移中进行数据更改时,我通常会回退到 SQL。可以使用 execute() 方法在迁移中执行任何 SQL 语句。要使用的确切 SQL 取决于所使用的数据库,但您应该能够提出适当的 db 查询。例如,在 MySQL 中,我相信以下内容应该有效:

 execute("UPDATE users SET access = 0 WHERE id IN (select id from users order by id limit 1);")

这是更多的未来证明。

于 2013-10-31T07:02:18.033 回答
1

迁移只是一种结构化的方式来进行数据库更改,包括模式和数据。在我看来,在某些情况下使用迁移来更改数据是合法的。

例如:

  1. 如果您在数据库中保存的数据大部分是不变的,但每年都在变化,那么每年进行一次迁移以更新它是可以的。例如,如果您列出足球联赛中的球队,则迁移将是每年更新当前球队的好方法。
  2. 如果要批量更改大表的属性。例如,如果您的用户中有一个 slug 列,并且名称“some user”将被转换为 slug“some_user”,现在您想将其更改为“some.user”。这是我在迁移时要做的事情。

话虽如此,我不会使用迁移来更改单个用户属性。如果这是偶尔发生的事情,您应该制作一个仪表板,以便您将来编辑此数据。否则,rake 任务可能是一个不错的选择。

于 2013-10-28T13:34:24.017 回答
1

如果操作正确,在正确的情况下使用迁移来迁移数据库中的数据并没有错。

在迁移中应该避免两件相关的事情(正如许多人提到的那样),这两者都不排除迁移数据:

  1. 在迁移中使用模型是不安全的。模型中的代码User可能会改变,当这种情况发生时,没有人会更新你的迁移,所以如果某个同事休假 3 个月,回来,并尝试运行她离开时发生的所有迁移,但是同时有人重命名了User模型,您的迁移将被破坏,并阻止她追赶。这只是意味着您必须使用 SQL,或者(如果您决心保持与迁移实现无关)直接在迁移文件中包含 ActiveRecord 模型的独立副本(嵌套在迁移类下)。

  2. 对种子数据使用迁移也没有意义,特别是当有人第一次设置应用程序时用于填充新数据库的数据,以便应用程序运行(或将具有一个全新的应用程序实例中所期望的数据)。您不能为此使用迁移,因为您在第一次设置数据库时不运行迁移,您运行db:schema:load. 因此,用于维护种子数据的特殊文件:seeds.rb. 这只是意味着,如果您确实需要在迁移中添加数据(以使生产和每个人的开发数据都跟上速度),并且它符合种子数据(应用程序运行所必需的),您需要将其添加到seeds.rb也!

但是,这些都不意味着您不应该使用迁移迁移现有数据库中的数据。这就是他们的目的。你应该使用它们!

于 2016-12-12T20:42:54.527 回答
0

如果我没记错的话,更改特定记录可能会起作用,但我不确定。

在任何情况下,这都不是一个好习惯,迁移应该只是模式更改的用户。为了更新一条记录,我会使用控制台。只需在终端中输入“rails console”并输入代码即可更改属性。

于 2013-10-15T20:09:37.023 回答
0

这个问题很老,我认为 Rails 方法随着时间的推移而改变。基于https://edgeguides.rubyonrails.org/active_record_migrations.html#migrations-and-seed-data可以在这里为新列提供数据。更准确地说,您的迁移代码还应包含“向下”块:

class DisableAccessForUser < ActiveRecord::Migration
  def up
    User.where(name: "User").first.update_column(:access, false)
  end
  
  def down
    User.where(name: "User").first.update_column(:access, true)
  end  
end

如果您使用seed.rb来预填充数据,请不要忘记在其中包含新的列值:

User.find_or_create_by(id: 0, name: 'User', access: false)
于 2021-06-10T08:25:14.567 回答