Rails 5:STI与很多通过协会

时间:2017-08-14 18:29:44

标签: ruby-on-rails activerecord associations has-many-through sti

我已经广泛搜索了我的情况的解决方案,但我找不到任何东西。

在我的应用程序中,我有Person模型存储有关人员的数据:

class Person < ApplicationRecord
end

然后我有一个Trial模型。试验可以让很多人使用多次通过关联。此外,在审判的情况下,一个人可以是被告原告。为此,我设置了这样的模型:

class Trial < ApplicationRecord
  has_many :trial_people
  has_many :plaintiffs, class_name: 'Plaintiff', through: :trial_people, source: :person
  has_many :defendants, class_name: 'Defendant', through: :trial_people, source: :person
end

class TrialPerson < ApplicationRecord
  belongs_to :trial
  belongs_to :person
end

class Plaintiff < Person
end

class Defendant < Person
end

然后我使用Select2 JQuery插件为视图中的每个试验添加被告和原告。获取强参数中的ID:

params.require(:trial).permit(:title, :description, :start_date, :plaintiff_ids => [], :defendant_ids => [])

这样我就能做到以下几点:

trial.defendants
trial.plaintiffs

问题是我没有办法区分trial_people表中的那些类。我在考虑在该表(STI)中添加type列,但在保存Trial对象时,我不知道如何自动将该类型添加到每个被告或原告。

非常感谢有关如何使用STI实现此目的的一些见解。

1 个答案:

答案 0 :(得分:1)

在不更改关联或架构的情况下,您可以使用before_create回调来实现此目的。

假设您已将person_type字符串列添加到trial_people

class TrialPerson < ApplicationRecord
  belongs_to :trial
  belongs_to :person
  before_create :set_person_type

  private

  def set_person_type
    self.person_type = person.type
  end
end

另一种方法是删除person关联并将其替换为多态triable关联。这实现了相同的最终结果,但它内置于ActiveRecord API中,因此不需要任何回调或额外的自定义逻辑。

# migration

class AddTriableReferenceToTrialPeople < ActiveRecord::Migration
  def up
    remove_reference :trial_people, :person, index: true
    add_reference :trial_people, :triable, polymorphic: true
  end

  def down
    add_reference :trial_people, :person, index: true
    remove_reference :trial_people, :triable, polymorphic: true
  end
end

# models

class TrialPerson < ApplicationRecord
  belongs_to :trial
  belongs_to :triable, polymorphic: true
end

class Person < ApplicationRecord
  has_many :trial_people, as: :triable
end

class Trial < ApplicationRecord
  has_many :trial_people
  has_many :defendants, source: :triable, source_type: 'Defendant', through: :trial_people
  has_many :plaintiffs, source: :triable, source_type: 'Plaintiff', through: :trial_people
end

class Plaintiff < Person
end

class Defendant < Person
end

这为您triable_type表格中的triable_idtrial_people列提供了添加到集合时自动设置的列

trial = Trial.create
trial.defendants << Defendant.first
trial.trial_people.first # => #<TrialPerson id: 1, trial_id: 1, triable_type: "Defendant", triable_id: 1, ... >