我想在Rails 4中使用STI。我已经有了一个模型Boilerplate
,现在我想继承一个BoilerplateOriginal
和一个BoilerplateCopy
模型。所以我在表格中添加了一列type
:
class AddTypeToBoilerplates < ActiveRecord::Migration
def up
add_column :boilerplates, :type, :string
Boilerplate.update_all type: 'BoilerplateOriginal'
change_column :boilerplates, :type, :string, null: false
end
def down
remove_column :boilerplates, :type
end
end
可悲的是,这个专栏似乎没有被Rails自动填充:
[1] a4aa2 » x = Boilerplate.new
=> #<Boilerplate:0x00000101609580> {
:id => nil,
:title => nil,
:type => nil
}
[2] a4aa2 » x.valid?
Boilerplate Exists (0.4ms) SELECT 1 AS one FROM "boilerplates" WHERE "boilerplates"."title" IS NULL LIMIT 1
=> false
[3] a4aa2 » x.errors
=> {
:title => [
[0] "must not be empty"
]
}
[4] a4aa2 » x.title = 'test'
=> "test"
[5] a4aa2 » x.valid?
Boilerplate Exists (0.1ms) SELECT 1 AS one FROM "boilerplates" WHERE "boilerplates"."title" = 'test' LIMIT 1
=> true
[6] a4aa2 » x.save
(0.1ms) begin transaction
Boilerplate Exists (0.2ms) SELECT 1 AS one FROM "boilerplates" WHERE "boilerplates"."title" = 'test' LIMIT 1
SQL (1.4ms) INSERT INTO "boilerplates" ("title") VALUES (?) [["title", "test"]]
SQLite3::ConstraintException: NOT NULL constraint failed: boilerplates.type: INSERT INTO "boilerplates" ("title") VALUES (?)
(0.1ms) rollback transaction
from /Users/josh/.rvm/gems/ruby-2.1.0@a4aa2/gems/sqlite3-1.3.10/lib/sqlite3/statement.rb:108:in `step'
我是否错过了重要的事情?我认为Rails只是填充了:type
列,当它可用时?
答案 0 :(得分:6)
好。你做错了当然。只有当您使用父<?xml version="1.0" encoding="UTF-8"?> <works xmlns="http://pbn.nauka.gov.pl/-/ns/bibliography" pbn-unit-id="1388"><article><title>Mukowiscydoza</title></article></works>
的任何子类创建对象时,才会设置type
列。但是,如果您使用Boilerplate
,则需要手动传递Boilerplate.new
值。另一方面,当您执行type
或BoilerplateCopy.new
时,默认情况下,ActiveRecord会将BoilerplateOriginal.new
设置为子类的类名。
阅读Single table inheritance的官方文档。
Active Record允许通过将类的名称存储在默认名为
type
的列中来进行继承(可以通过覆盖type
来更改)。这意味着继承看起来像这样:Base.inheritance_column
当您执行
class Company < ActiveRecord::Base; end class Firm < Company; end class Client < Company; end class PriorityClient < Client; end
时,此记录将保存在公司表格中Firm.create(name: "37signals")
。然后,您可以使用type = “Firm”
再次获取此行,它将返回Company.where(name: '37signals').first
个对象。