为什么ActiveRecord在STI模型的类型列中插入NULL?

我正在从DataMapper移植一个非常大的Rails项目到ActiveRecord。 必须移植的模型中有一组用户模型,它们使用单​​表继承(STI)来区分一种类型和另一种类型。 以下是它的一个简化版本:

class User < ActiveRecord::Base
  ...
end

class AdminUser < User
  ...
end

通常,'type'字段用于通过存储正在保存的对象的类名称(即'AdminUser')来区分用户和AdminUser之间的区别。 它在开发中可以正常工作,但是当我在测试环境中尝试User.create时,我得到:

ActiveRecord::StatementInvalid: Mysql::Error: Column 'type' cannot be null

ActiveRecord会尝试插入一个新行,将类型列设置为NULL ...可能会导致在测试环境中发生这种情况,但在开发中不会发生这种情况?


事实证明,这是数据库表本身的一个细微差异,导致ActiveRecord的行为发生变化。 测试数据库没有type列的默认值,而在开发中,默认值是'User' 。 显然,ActiveRecord在为主类类型的对象(从ActiveRecord :: Base继承的类 - 在本例中为User )插入数据时使用默认值。 为什么它不只是使用类名是超出我的理解!

当我更新我的开发数据库以获得类型列的默认值时(我确实知道它是需要的),我真的很困惑,因为生产数据库已经有了一个,所以我的开发数据库很明显是不同步的。 所以我这样做了:

mysql> ALTER TABLE users MODIFY COLUMN type varchar(50) NOT NULL DEFAULT 'User';
...[ok]
mysql> exit
Bye
$> bundle exec rake db:test:prepare # <-- My Mistake
...[ok]

我以为这就是我所要做的,但事实证明,运行db:test:prepare只是将您的测试数据库与您的schema.rb文件相匹配,并且我的schema.rb文件尚未更新,因此User.create运行在开发中,但在测试中爆发:D

最后,我开始理解上述所有内容,除此之外,我还需要运行db:migrate以更新我的schema.rb文件,然后再运行db:test:prepare 。 一旦我做到了:瞧! User.create实际上使用了type列的默认值来插入新的用户对象。

故事的道德启示:

  • 切勿让开发数据库与生产不同步。 如果是这样的话:用db:schema:load将它吹走,并用新的开发数据重新开始! (或获得生产转储或其他东西)
  • 明智地选择你的ORM。 RIP DataMapper - 我会想念你优雅的抽象......但不是你的错误。

  • 使用不同于“type”的列名称

    链接地址: http://www.djcxy.com/p/49733.html

    上一篇: Why is ActiveRecord inserting NULL in the type column of an STI model?

    下一篇: ActiveRecord Validation: based on attribute or function