Rails迁移:仅用于架构更改或更新数据?

时间:2013-10-15 17:33:15

标签: ruby-on-rails migration

我是初级Rails开发人员,在工作中我们面临以下问题:

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

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

迁移仅适用于架构更改吗?

您建议使用其他哪些解决方案?

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

7 个答案:

答案 0 :(得分:16)

简短版本是,因为迁移仅用于架构更改,所以您不希望使用它们来更改数据库中的实际数据。

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

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

希望漫无边际。

<强>更新

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

  • Rails Guide for Migrations - Using Models in your Migrations。本节介绍了迁移文件中的数据操作可能导致其他开发人员出现问题的场景。
  • Rails Guide for Migrations - Migrations and Seed Data。与上面相同的文档并没有真正解释为什么在迁移中放置种子或数据操作是不好的,只是说把所有这些都放在seed.rd文件中。
  • This SO answer。这个人基本上说的是我上面写的相同内容,除了它们提供了 Agile Web Development with Rails(第3版)一书的引用,部分由 David Heinemeier Hansson 撰写, Rails的创建者。我不会复制引用,因为您可以在该帖子中阅读它,但我相信它可以让您更好地了解为什么迁移中的种子或数据操作可能被视为不良做法。

答案 1 :(得分:2)

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

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

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

每当我们从Git更新代码时,调用NameSpace中的所有rake任务。

答案 2 :(得分:1)

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

例如:

  1. 如果您持有的数据在数据库中大部分是不变的,但每年都会更改,那么每年进行一次迁移就可以更新了。例如,如果您列出足球联赛中的球队,那么迁移将是每年更新当前球队的好方法。
  2. 如果要批量更改大表的属性。例如,如果您的用户中有一个slug列,并且名称“some user”将被转换为slug“some_user”,现在您想将其更改为“some.user”。这是我对迁移所做的事情。
  3. 话虽如此,我不会使用迁移来更改单个用户属性。如果这是偶尔发生的事情,你应该制作一个仪表板,以便将来编辑这些数据。否则,佣金任务可能是一个不错的选择。

答案 3 :(得分:1)

使用迁移中的类进行数据更改是危险的,因为它不是未来的证据。对类的更改很容易在将来中断迁移。

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

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

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

这是未来的证据。

答案 4 :(得分:0)

如果我没记错的话,更改特定记录可能有效,但我不确定。

在任何情况下,这都不是一个好习惯,只有用户才能进行架构更改。 要更新一条记录,我会使用控制台。只需在终端输入“rails console”并输入代码即可更改属性。

答案 5 :(得分:0)

使用迁移迁移数据库中的数据是没有错的,如果你做得对的话,在正确的情况下。

迁移过程中应该避免两件相关的事情(正如许多人所提到的),这两件事都不能阻止迁移数据:

  1. 在迁移中使用模型是不安全的。 User模型中的代码可能会发生变化,当发生这种情况时,没有人会更新您的迁移,因此,如果某个同事休假3个月,请回来,并尝试运行所发生的所有迁移虽然她已经离开了,但是有人在同一时间重新命名了User模型,你的移民将被打破,并阻止她赶上来。这只是意味着你必须使用SQL,或者(如果你决定让你的迁移实现不可知)直接在你的迁移文件中包含一个ActiveRecord模型的独立副本(嵌套在迁移类下)。

    < / LI>
  2. 对种子数据使用迁移也没有意义,特别是当有人首次设置应用程序时,用于填充新数据库的数据,因此应用程序将运行(或将拥有应用程序的全新实例中预期的数据)。您无法使用迁移,因为您在首次设置数据库时未运行迁移,而是运行db:schema:load。因此,维护种子数据的特殊文件:seeds.rb。这只是意味着如果你确实需要在迁移中添加数据(为了让生产和每个人的dev数据加速),它就有资格作为种子数据(运行应用程序所必需的) ,您还需要将其添加到seeds.rb

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

答案 6 :(得分: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

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

User.find_or_create_by(id: 0, name: 'User', access: false)