Skip to content

Commit d3c818d

Browse files
committed
Remove the indirection - resources manage their own Person objects*
Remove the data migration for now, needs to be safer/better. * This saves having to centrally manage People and provide ways of correcting metadata etc.
1 parent ba745c9 commit d3c818d

18 files changed

Lines changed: 113 additions & 240 deletions

app/controllers/materials_controller.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,12 +171,12 @@ def material_params
171171
:content_provider_id, :difficulty_level, :version, :status,
172172
:date_created, :date_modified, :date_published, :other_types,
173173
:prerequisites, :syllabus, :visible, :learning_objectives, { subsets: [] },
174-
{ contributors: [] }, { target_audience: [] },
174+
{ authors: [] }, { contributors: [] }, { target_audience: [] },
175175
{ collection_ids: [] }, { keywords: [] }, { resource_type: [] },
176176
{ scientific_topic_names: [] }, { scientific_topic_uris: [] },
177177
{ operation_names: [] }, { operation_uris: [] },
178178
{ node_ids: [] }, { node_names: [] }, { fields: [] },
179-
person_links_attributes: [:id, :role, :_destroy, person_attributes: %i[id given_name family_name full_name first_name last_name orcid]],
179+
people_attributes: %i[id role _destroy given_name family_name full_name first_name last_name orcid],
180180
external_resources_attributes: %i[id url title _destroy],
181181
external_resources: %i[url title],
182182
event_ids: [], locked_fields: [])

app/models/concerns/has_people.rb

Lines changed: 11 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,66 +2,40 @@ module HasPeople
22
extend ActiveSupport::Concern
33

44
included do
5-
has_many :person_links, as: :resource, dependent: :destroy
6-
has_many :people, through: :person_links
7-
accepts_nested_attributes_for :person_links, allow_destroy: true, reject_if: :all_blank
5+
has_many :people, as: :resource, dependent: :destroy, inverse_of: :resource
6+
accepts_nested_attributes_for :people, allow_destroy: true, reject_if: :all_blank
87
end
98

109
class_methods do
1110
# Define a person role association (e.g., :authors, :contributors)
1211
# This creates the association and a custom setter that accepts strings, hashes, or Person objects
1312
def has_person_role(role_name, role_key: role_name.to_s.singularize)
1413
# Define the association
15-
has_many role_name, -> { where(person_links: { role: role_key }) }, through: :person_links, source: :person
14+
has_many role_name, -> { where(role: role_key) }, class_name: 'Person', as: :resource, inverse_of: :resource
1615

1716
# Define custom setter that accepts strings (legacy), hashes, or Person objects
1817
define_method("#{role_name}=") do |value|
19-
set_people_for_role(value, role_key)
18+
super(set_people_for_role(value, role_key))
2019
end
2120
end
2221
end
2322

2423
private
2524

2625
# Set people for a specific role, accepting various input formats
27-
def set_people_for_role(value, role)
28-
return if value.nil?
29-
30-
# Convert to array if needed
31-
people_array = Array(value).reject(&:blank?)
32-
26+
def set_people_for_role(value, role_key)
3327
# Remove existing links for this role
34-
person_links.where(role: role).destroy_all
28+
people.where(role: role_key).destroy_all
3529

36-
people_array.each do |person_data|
30+
Array(value).reject(&:blank?).map do |person_data|
3731
if person_data.is_a?(String)
3832
# Legacy format: store as full_name directly
39-
person = Person.find_or_create_by!(full_name: person_data.strip)
40-
person_links.build(person: person, role: role)
33+
people.build(full_name: person_data.strip, role: role_key)
4134
elsif person_data.is_a?(Hash)
42-
# Hash format from API - supports both legacy (first_name/last_name) and new (given_name/family_name) field names
43-
given_name = person_data[:given_name] || person_data['given_name'] || person_data[:first_name] || person_data['first_name']
44-
family_name = person_data[:family_name] || person_data['family_name'] || person_data[:last_name] || person_data['last_name']
45-
full_name = person_data[:full_name] || person_data['full_name']
46-
orcid = person_data[:orcid] || person_data['orcid']
47-
48-
# Prefer full_name if provided, otherwise use given_name and family_name
49-
if full_name.present?
50-
person = Person.find_or_create_by!(full_name: full_name)
51-
elsif given_name.present? && family_name.present?
52-
person = Person.find_or_create_by!(given_name: given_name, family_name: family_name)
53-
elsif given_name.present? || family_name.present?
54-
# If only one part is provided, treat it as full_name
55-
person = Person.find_or_create_by!(full_name: "#{given_name}#{family_name}".strip)
56-
else
57-
next # Skip if no name data provided
58-
end
59-
60-
person.update!(orcid: orcid) if orcid.present?
61-
person_links.build(person: person, role: role)
35+
people.build(**person_data, role: role_key)
6236
elsif person_data.is_a?(Person)
63-
# Person object
64-
person_links.build(person: person_data, role: role)
37+
person_data.role = role_key
38+
person_data
6539
end
6640
end
6741
end

app/models/person.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ class Person < ApplicationRecord
22
include HasOrcid
33

44
belongs_to :profile, optional: true
5-
has_many :person_links, dependent: :destroy
5+
belongs_to :resource, polymorphic: true
6+
7+
validates :resource, :role, presence: true
68

79
# Validate that at least a full_name OR both given_name and family_name are present
810
validate :name_presence

app/models/person_link.rb

Lines changed: 0 additions & 7 deletions
This file was deleted.

app/views/common/_person_form.html.erb

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,25 @@
11
<% index ||= 'replace-me' %> <%# This is so we can render a blank version of this sub-form in the page, %>
22
<%# which can be dynamically cloned using JavaScript to add more People to the main form %>
3-
<% field_name_prefix = "#{form_name}[person_links_attributes][#{index}]" %> <%# This format is dictated by "accepts_nested_attributes_for" %>
3+
<% field_name_prefix = "#{form_name}[people_attributes][#{index}]" %> <%# This format is dictated by "accepts_nested_attributes_for" %>
44

55
<div class="form-inline person-form" data-index="<%= index -%>" data-role="<%= role -%>">
6-
<%= hidden_field_tag("#{field_name_prefix}[id]", person_link&.id) %>
6+
<%= hidden_field_tag("#{field_name_prefix}[id]", person&.id) %>
77
<%= hidden_field_tag("#{field_name_prefix}[role]", role) %>
8-
<%= hidden_field_tag("#{field_name_prefix}[person_attributes][id]", person_link&.person&.id) %>
98

109
<div class="form-group">
11-
<%= text_field_tag "#{field_name_prefix}[person_attributes][full_name]", person_link&.person&.full_name, :class => 'form-control person-full-name', :placeholder => 'Full Name' %>
10+
<%= text_field_tag "#{field_name_prefix}[person_attributes][full_name]", person&.full_name, :class => 'form-control person-full-name', :placeholder => 'Full Name' %>
1211
</div>
1312

1413
<div class="form-group">
15-
<%= text_field_tag "#{field_name_prefix}[person_attributes][given_name]", person_link&.person&.given_name, :class => 'form-control person-given-name', :placeholder => 'Given Name (optional)' %>
14+
<%= text_field_tag "#{field_name_prefix}[person_attributes][given_name]", person&.given_name, :class => 'form-control person-given-name', :placeholder => 'Given Name (optional)' %>
1615
</div>
1716

1817
<div class="form-group">
19-
<%= text_field_tag "#{field_name_prefix}[person_attributes][family_name]", person_link&.person&.family_name, :class => 'form-control person-family-name', :placeholder => 'Family Name (optional)' %>
18+
<%= text_field_tag "#{field_name_prefix}[person_attributes][family_name]", person&.family_name, :class => 'form-control person-family-name', :placeholder => 'Family Name (optional)' %>
2019
</div>
2120

2221
<div class="form-group">
23-
<%= text_field_tag "#{field_name_prefix}[person_attributes][orcid]", person_link&.person&.orcid, :class => 'form-control person-orcid', :placeholder => 'ORCID (optional)' %>
22+
<%= text_field_tag "#{field_name_prefix}[person_attributes][orcid]", person&.orcid, :class => 'form-control person-orcid', :placeholder => 'ORCID (optional)' %>
2423
</div>
2524

2625
<label class="ml-2 delete-person-btn">

app/views/materials/_form.html.erb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@
7373
<%= f.field_lock :authors %>
7474

7575
<div id="person-author-list">
76-
<% @material.person_links.where(role: 'author').each_with_index do |person_link, index| %>
76+
<% @material.people.where(role: 'author').each_with_index do |person, index| %>
7777
<%= render partial: 'common/person_form',
78-
locals: { form_name: 'material', index: index, person_link: person_link, role: 'author' } %>
78+
locals: { form_name: 'material', index: index, person: person, role: 'author' } %>
7979
<% end %>
8080
</div>
8181

@@ -91,9 +91,9 @@
9191
<%= f.field_lock :contributors %>
9292

9393
<div id="person-contributor-list">
94-
<% @material.person_links.where(role: 'contributor').each_with_index do |person_link, index| %>
94+
<% @material.people.where(role: 'contributor').each_with_index do |person, index| %>
9595
<%= render partial: 'common/person_form',
96-
locals: { form_name: 'material', index: "contributor_#{index}", person_link: person_link, role: 'contributor' } %>
96+
locals: { form_name: 'material', index: "contributor_#{index}", person: person, role: 'contributor' } %>
9797
<% end %>
9898
</div>
9999

@@ -225,12 +225,12 @@
225225

226226
<div id="person-author-template" style="display: none">
227227
<%= render partial: 'common/person_form',
228-
locals: { form_name: 'material', person_link: nil, role: 'author' } %>
228+
locals: { form_name: 'material', person: nil, role: 'author' } %>
229229
</div>
230230

231231
<div id="person-contributor-template" style="display: none">
232232
<%= render partial: 'common/person_form',
233-
locals: { form_name: 'material', person_link: nil, role: 'contributor' } %>
233+
locals: { form_name: 'material', person: nil, role: 'contributor' } %>
234234
</div>
235235

236236
<script type="text/javascript">

db/migrate/20251119095245_create_person_links.rb

Lines changed: 0 additions & 14 deletions
This file was deleted.

db/migrate/20251119095246_migrate_material_authors_data.rb

Lines changed: 0 additions & 56 deletions
This file was deleted.

db/migrate/20251119095247_remove_authors_from_materials.rb

Lines changed: 0 additions & 6 deletions
This file was deleted.

db/migrate/20251119095244_create_people.rb renamed to db/migrate/20260211143944_create_people.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ def change
55
t.string :family_name
66
t.string :full_name
77
t.string :orcid
8+
t.string :role, null: false
9+
t.references :resource, polymorphic: true, null: false
810
t.references :profile, null: true, foreign_key: true
911

1012
t.timestamps
1113
end
1214

1315
add_index :people, :orcid
16+
add_index :people, [:resource_type, :resource_id, :role]
1417
end
1518
end

0 commit comments

Comments
 (0)