【问题标题】:How to fix commits with conflicting migrations?如何修复具有冲突迁移的提交?
【发布时间】:2016-02-15 01:58:42
【问题描述】:

假设有一个创建一些记录的迁移,并且有两个看起来像这样的提交

# commit 1 by Alice
# migration
def up
    create_table :cities do |t|
        t.string :name
    end
    City.create!(name: 'New York')
    City.create!(name: 'Moscow')
end

# commit 2 by Bob
# migration
def change
    change_table :cities do |t|
        t.boolean :capital
    end
end
# model
class City
    before_create :set_capital

    def set_capital
        capital = false
    end
end

现在,如果第三个人拉动代码迁移将失败,因为capital 属性将不存在。有没有办法补救这种情况?

【问题讨论】:

  • 首先不要使用迁移来创建记录 - 只需使用它们来更改数据库架构。这就是种子文件的用途。所以解雇爱丽丝:)
  • 如果你纠正了当第三人克隆 repo 并运行 rake db:migrate 时迁移会失败的原因并没有明显的原因 - 迁移并没有真正关心你的模型或你的 @987654324 @ 筛选。他们只是改变了数据库架构。
  • 如果你必须解决这个问题,你将创建一个新的提交,从 Alice 的错误迁移文件中删除 City.create!(name: 'Moscow')

标签: ruby-on-rails ruby activerecord rails-activerecord rails-migrations


【解决方案1】:

我会在这里做两件事:

  1. 不允许在 capital 列中使用 NULL。允许 NULL 是 Rails 的默认设置,但它几乎总是错误的选择,因此请手动将列设为 NOT NULL。您可能也希望将其应用于表中的所有其他列:如果您不能证明允许在列中使用 NULL,请将其设为 NOT NULL。

  2. capital 列包含一个默认值——在数据库中,而不仅仅是在你的Rails 代码中。

这将使迁移 2 看起来像:

change_table :cities do |t|
    t.boolean :capital, :null => false, :default => false
end

如果您同时执行这两项操作,那么数据库将在添加新列时填写默认值,您的问题就会消失。

我倾向于将数据库视为一个完全独立的应用程序,其接口恰好是隐藏在 ActiveRecord 或其他一些 ORM 后面的 SQL(大部分)。

我也同意评论者的观点,即在迁移中使用模型是一个坏主意。


顺便说一句,您的 set_capital 方法并没有按照您的想法执行。你想说:

def set_capital
    self.capital = false
    true
end

capital = false只创建一个局部变量,然后set_capital会返回false;所以你的set_capital 不会初始化capital 属性和before_* callback return false will stop everything in its tracks

取消回调

如果before_* 回调返回false,则取消所有后续回调和相关操作。

【讨论】:

  • 代码只是以下情况的一个人为示例 - 有人使用迁移创建一个表并用数据填充它,然后添加一个before_create 以使之前的迁移仅可用由获得非常具体的代码库快照的人提供。
  • 那么真正的解决方案将取决于具体情况。经验法则:(1) 将数据库视为一个单独的应用程序,而不仅仅是 Web 应用程序的一个组件。 (2) 不要在迁移中使用模型,通过直接与数据库对话来完成所有需要完成的工作,而无需 ORM 或模型。
猜你喜欢
  • 2020-10-17
  • 2016-08-07
  • 2020-07-28
  • 2021-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-24
  • 2019-10-02
相关资源
最近更新 更多