Rails 5:STI 与直通关联
Rails 5: STI With Has Many Through Association
我已经广泛搜索了针对我的情况的解决方案,但我找不到任何东西。
在我的应用程序中,我有一个 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
table 中的那些 类。我正在考虑向 table (STI) 添加一个 type
列,但我不知道如何在保存 Trial 对象时自动将该类型添加到每个被告或原告。
希望了解如何实现这一点,是否使用 STI。
您可以在不更改关联或架构的情况下执行此操作的一种方法是使用 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
这会在 trial_people
table 上为您提供 triable_type
和 triable_id
列,当您添加到 collections[=21= 时,它们会自动设置]
trial = Trial.create
trial.defendants << Defendant.first
trial.trial_people.first # => #<TrialPerson id: 1, trial_id: 1, triable_type: "Defendant", triable_id: 1, ... >
我已经广泛搜索了针对我的情况的解决方案,但我找不到任何东西。
在我的应用程序中,我有一个 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
table 中的那些 类。我正在考虑向 table (STI) 添加一个 type
列,但我不知道如何在保存 Trial 对象时自动将该类型添加到每个被告或原告。
希望了解如何实现这一点,是否使用 STI。
您可以在不更改关联或架构的情况下执行此操作的一种方法是使用 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
这会在 trial_people
table 上为您提供 triable_type
和 triable_id
列,当您添加到 collections[=21= 时,它们会自动设置]
trial = Trial.create
trial.defendants << Defendant.first
trial.trial_people.first # => #<TrialPerson id: 1, trial_id: 1, triable_type: "Defendant", triable_id: 1, ... >