如何使用不同名称多次使用同一模型?

时间:2017-05-01 13:05:39

标签: ruby-on-rails

我有一个Person类,我想代表贡献者,如委员会的主席和副主席(以及后来的其他事情)。所以在我的委员会课程中,我想使用Person类来提供一个主席和许多副主席:

  • 委员会有许多副主席
  • 委员会有一位主席

Chairs和ViceChairs都是人。

我期待说

class Committee < ActiveRecord::Base
    has_many :vice_chairs, class_name: 'People'
    has_one  :chair, class_name: 'People'
end

class Person < ActiveRecord::Base
    belongs_to :group, foreign_key: 'vice_chair_id'
    belongs_to :group, foreign_key: 'chair_id'
end

这是正确的方法吗?

更新:我被建议使用Single Table Inheritance来解决此问题。我改变了我的代码:

class Person < ActiveRecord::Base
end

class Chair < Person
end

class ViceChair < Person
end

class CreatePeople < ActiveRecord::Migration
  def change
    create_table :people do |t|
      t.string :type
      t.string :first_name
      t.string :last_name
      t.string :email
      t.string :affiliation

      t.timestamps null: false
    end
  end
end

这会有用吗?如何编写迁移以支持此操作?

2 个答案:

答案 0 :(得分:2)

根据模型类型要求略有不同的行为但属性相同的用例,最好使用单表继承[1]。

所以我建议如下:

<强>型号:

class Group < ApplicationRecord
  has_many :vice_chairs
  has_one :chair
end

class Person < ApplicationRecord
  belongs_to :group
end

class ViceChair < Person
  belongs_to :group
end

class Chair < Person
  belongs_to :group
end

<强>迁移

class CreateGroups < ActiveRecord::Migration[5.0]
  def change
    create_table :groups do |t|
      t.string :name

      t.timestamps
    end
  end
end

class CreatePeople < ActiveRecord::Migration[5.0]
  def change
    create_table :people do |t|
      t.string :type
      t.string :full_name
      t.integer :age
      t.references :group, foreign_key: true

      t.timestamps
    end
  end
end

使用示例:

# create some test data
grp = Group.create!(name: "superheros")
vc = ViceChair.create!(full_name: "Superman Sam")
c = Chair.create!(full_name: "Batman Bob")
p = Person.create!(full_name: "Regular John Doe")

# add to group's ViceChairs
grp.vice_chairs << vc 

# add Chair to group
grp.chair = c
grp.save!

# Convert person to vice chair
p.type = "ViceChair"
p.save!
new_vc = ViceChair.where(full_name: p.full_name).first
grp.vice_chairs << new_vc
grp.vice_chairs.count
# => 2

rails CLI命令:

rails generate model Group name
rails generate model Person type full_name age:integer group:references:index
rails generate model ViceChair group:references --parent=Person
rails generate model Chair group:references --parent=Person

处理管理主席变更的业务逻辑:

您需要添加一些自定义逻辑来管理主席关联,而无需创建悬空椅。我建议将一个实例方法添加到Group类中add_chairremove_chair,然后您需要决定将Person从主席位置移除时会发生什么。他们可能成为一个普通人。在这种情况下,您可以将类型设置为nil

享受!

[1]有关STI http://guides.rubyonrails.org/association_basics.html#single-table-inheritance

的更多信息

答案 1 :(得分:0)

如果您的公共字段具有不同的型号名称,那么只需在表格中添加类型字段即可使用Single Table Inheritance。该字段包含型号名称。

您可以参考以下链接获取单表继承https://github.com/maxime1992/angular-ngrx-starter