2

I have searched extensively for a solution to my situation, but I can't find anything.

In my application I have a Person model that only stores data about people:

class Person < ApplicationRecord
end

Then I have a Trial model. Trials can have many people using a has-many-through association. Additionally, in the context of a Trial, a person can be a Defendant or a Plaintiff. To achieve this, I set up my models like this:

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

I am then using Select2 JQuery plugin to add in the defendants and plaintiffs for each trial in the view. Obtaining the IDs in strong parameters:

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

So that I can do achieve like the following:

trial.defendants
trial.plaintiffs

The problem is that I do not have any way of distinguishing between those classes inside the trial_people table. I was thinking on adding a type column to that table (STI), but I do not know how to automatically add that type to each defendant or plaintiff when saving the Trial object.

Would appreciate some insight on how to achieve this, using STI or not.

Andres
  • 75
  • 8
  • the `type` column would be a bad idea since it is a reserved word in Rails. You could use a different name, like `trial_role` which could be either `plaintiff` or `defendant`, and be selected as you create this `TrialPerson` record with a simple radio button or a select tag. – MrYoshiji Aug 14 '17 at 19:02
  • I am aware of the `type` column. The thing is, I have one multiple select field for plaintiffs, and another multiple select field for defendants. So what I need is that this `type` or trial_role` to be set automatically. – Andres Aug 14 '17 at 19:18

1 Answers1

2

One way you can go about this without changing your associations or schema is to use a before_create callback.

Assuming you've added a person_type string column to 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

Another way to approach it is to remove the person association and replace it with a polymorphic triable association. This achieves the same end result but it's built into the ActiveRecord API and so doesn't require any callbacks or extra custom logic.

# 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

This gives you triable_type and triable_id columns on your trial_people table which are set automatically when you add to the collections

trial = Trial.create
trial.defendants << Defendant.first
trial.trial_people.first # => #<TrialPerson id: 1, trial_id: 1, triable_type: "Defendant", triable_id: 1, ... >
m. simon borg
  • 2,515
  • 12
  • 20