Rails单表继承:类型coumn未自动填充

时间:2015-08-14 08:48:02

标签: ruby-on-rails single-table-inheritance

我想在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列,当它可用时?

1 个答案:

答案 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值。另一方面,当您执行typeBoilerplateCopy.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个对象。