Class: Person

Inherits:
ApplicationRecord show all
Includes:
Housekeeping::Timestamps, Housekeeping::Users, Shared::AlternateValues, Shared::DataAttributes, Shared::HasPapertrail, Shared::Identifiable, Shared::IsData, Shared::Notable, Shared::SharedAcrossProjects
Defined in:
app/models/person.rb

Overview

A human. Data only, not users. There are two classes of people: vetted and unvetted.

A vetted person

  • Has two or more roles

  • Has one or more annotations

An unvetted person

  • Has no or 1 role

  • Has no annotations

A unvetted person becomes automatically vetted when they have > 1 roles or they have an annotation associated with them.

Direct Known Subclasses

Unvetted, Vetted

Defined Under Namespace

Classes: Unvetted, Vetted

Constant Summary

ALTERNATE_VALUES_FOR =

Class constants

[:last_name, :first_name]

Instance Attribute Summary (collapse)

Attributes included from Housekeeping::Users

#by

Class Method Summary (collapse)

Instance Method Summary (collapse)

Methods included from Housekeeping::Timestamps

#data_breakdown_for_chartkick_recent

Methods included from Housekeeping::Users

#set_created_by_id, #set_updated_by_id

Methods included from ActiverecordUtilities

#trim_attributes

Instance Attribute Details

- (String) cached

TODO:

Returns:

  • (String)


34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'app/models/person.rb', line 34

class Person < ApplicationRecord
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::HasPapertrail 
  include Shared::IsData

  # Class constants
  ALTERNATE_VALUES_FOR = [:last_name, :first_name]

  validates_presence_of :last_name, :type
  before_validation :set_type_if_blank

  # after_save :update_bibtex_sources
  after_save :set_cached

  validates :type, inclusion: {in:      ['Person::Vetted', 'Person::Unvetted'],
                               message: "%{value} is not a validly_published type"}

  has_many :roles, dependent: :destroy, inverse_of: :person
  has_many :author_roles, class_name: 'SourceAuthor'
  has_many :editor_roles, class_name: 'SourceEditor'
  has_many :source_roles, class_name: 'SourceSource'
  has_many :collector_roles, class_name: 'Collector'
  has_many :determiner_roles, class_name: 'Determiner'
  has_many :taxon_name_author_roles, class_name: 'TaxonNameAuthor'
  has_many :type_designator_roles, class_name: 'TypeDesignator'
  has_many :georeferencer_roles, class_name: 'Georeferencer'

  # has_many :sources, through: :roles   # TODO: test and confirm dependent

  has_many :authored_sources, through: :author_roles, source: :role_object, source_type: 'Source::Bibtex'
  has_many :edited_sources, through: :editor_roles, source: :role_object, source_type: 'Source::Bibtex'
  has_many :human_sources, through: :source_roles, source: :role_object, source_type: 'Source::Human'
  has_many :collecting_events, through: :collector_roles, source: :role_object, source_type: 'CollectingEvent'
  has_many :taxon_determinations, through: :determiner_roles, source: :role_object, source_type: 'TaxonDetermination'
  has_many :taxon_name_authors, through: :taxon_name_author_roles, source: :role_object, source_type: 'TaxonName'
  has_many :type_material, through: :type_designator_roles, source: :role_object, source_type: 'TypeMaterial'
  has_many :georeferences, through: :georeferencer_roles, source: :role_object, source_type: 'Georeference'

  #scope :named, -> (name) {where(name: name)}
  #scope :named_smith, where(last_name: 'Smith')
  scope :named_smith, -> { where(last_name: 'Smith') }
  #scope :smith_start, -> {where(last_name: start_with?('Smith'))}  # have tried multiple ways to select records where last_name like 'Smith%' without success
  scope :created_before, -> (time) { where('created_at < ?', time) }
  scope :with_role, -> (role) { includes(:roles).where(roles: {type: role}) }
  scope :ordered_by_last_name, -> { order(:last_name) }

  def name
    [self.first_name, self.prefix, self.last_name, self.suffix].compact.join(' ').strip
  end

  # @return [String]
  #   The person's name in BibTeX format (von last, Jr, first)
  def bibtex_name
    out = ''
    out << self.prefix + ' ' unless self.prefix.blank?
    out << self.last_name unless self.last_name.blank?
    out << ', ' unless out.blank? || (self.first_name.blank? && self.suffix.blank?)
    out << self.suffix unless self.suffix.blank?
    out << ', ' unless out.end_with?(', ') || self.first_name.blank? || out.blank?
    out << self.first_name unless self.first_name.blank?
    out.strip
  end

  # @return [String]
  #   The person's full last name including prefix & suffix (von last Jr)
  def full_last_name
    out = ''
    out << self.prefix + ' ' unless self.prefix.blank?
    out << self.last_name unless self.last_name.blank?
    out << ' ' + self.suffix unless self.suffix.blank?
    out.strip
  end

  def is_author?
    self.author_roles.to_a.length > 0
  end

  def is_editor?
    self.editor_roles.to_a.length > 0
  end

  def is_source?
    self.source_roles.to_a.length > 0
  end

  def is_collector?
    self.collector_roles.to_a.length > 0
  end

  def is_determiner?
    self.determiner_roles.to_a.length > 0
  end

  def is_taxon_name_author?
    self.taxon_name_author_roles.to_a.length > 0
  end

  def is_type_designator?
    self.type_designator_roles.to_a.length > 0
  end

  def is_georeferencer?
    self.georeferencer_roles.to_a.length > 0
  end

  # TODO: TEST!
  def self.parser(name_string)
    BibTeX::Entry.new(type: :book, author: name_string).parse_names.to_citeproc['author']
  end

  # TODO: TEST!
  def self.parse_to_people(name_string)
    self.parser(name_string).collect { |n| Person::Unvetted.new(last_name: n['family'], first_name: n['given'], prefix: n['non-dropping-particle']) }
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  protected

  def set_type_if_blank
    self.type = 'Person::Unvetted' if self.type.blank?
  end

  def self.find_for_autocomplete(params)
    where('cached ILIKE ? OR cached ILIKE ? OR cached = ?', "#{params[:term]}%", "%#{params[:term]}%", params[:term])
  end

  def set_cached
    update_column(:cached, self.bibtex_name) if errors.empty? 
  end

end

- (String) first name(name)

the first name, includes initials if the are provided

Returns:

  • (String)


34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'app/models/person.rb', line 34

class Person < ApplicationRecord
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::HasPapertrail 
  include Shared::IsData

  # Class constants
  ALTERNATE_VALUES_FOR = [:last_name, :first_name]

  validates_presence_of :last_name, :type
  before_validation :set_type_if_blank

  # after_save :update_bibtex_sources
  after_save :set_cached

  validates :type, inclusion: {in:      ['Person::Vetted', 'Person::Unvetted'],
                               message: "%{value} is not a validly_published type"}

  has_many :roles, dependent: :destroy, inverse_of: :person
  has_many :author_roles, class_name: 'SourceAuthor'
  has_many :editor_roles, class_name: 'SourceEditor'
  has_many :source_roles, class_name: 'SourceSource'
  has_many :collector_roles, class_name: 'Collector'
  has_many :determiner_roles, class_name: 'Determiner'
  has_many :taxon_name_author_roles, class_name: 'TaxonNameAuthor'
  has_many :type_designator_roles, class_name: 'TypeDesignator'
  has_many :georeferencer_roles, class_name: 'Georeferencer'

  # has_many :sources, through: :roles   # TODO: test and confirm dependent

  has_many :authored_sources, through: :author_roles, source: :role_object, source_type: 'Source::Bibtex'
  has_many :edited_sources, through: :editor_roles, source: :role_object, source_type: 'Source::Bibtex'
  has_many :human_sources, through: :source_roles, source: :role_object, source_type: 'Source::Human'
  has_many :collecting_events, through: :collector_roles, source: :role_object, source_type: 'CollectingEvent'
  has_many :taxon_determinations, through: :determiner_roles, source: :role_object, source_type: 'TaxonDetermination'
  has_many :taxon_name_authors, through: :taxon_name_author_roles, source: :role_object, source_type: 'TaxonName'
  has_many :type_material, through: :type_designator_roles, source: :role_object, source_type: 'TypeMaterial'
  has_many :georeferences, through: :georeferencer_roles, source: :role_object, source_type: 'Georeference'

  #scope :named, -> (name) {where(name: name)}
  #scope :named_smith, where(last_name: 'Smith')
  scope :named_smith, -> { where(last_name: 'Smith') }
  #scope :smith_start, -> {where(last_name: start_with?('Smith'))}  # have tried multiple ways to select records where last_name like 'Smith%' without success
  scope :created_before, -> (time) { where('created_at < ?', time) }
  scope :with_role, -> (role) { includes(:roles).where(roles: {type: role}) }
  scope :ordered_by_last_name, -> { order(:last_name) }

  def name
    [self.first_name, self.prefix, self.last_name, self.suffix].compact.join(' ').strip
  end

  # @return [String]
  #   The person's name in BibTeX format (von last, Jr, first)
  def bibtex_name
    out = ''
    out << self.prefix + ' ' unless self.prefix.blank?
    out << self.last_name unless self.last_name.blank?
    out << ', ' unless out.blank? || (self.first_name.blank? && self.suffix.blank?)
    out << self.suffix unless self.suffix.blank?
    out << ', ' unless out.end_with?(', ') || self.first_name.blank? || out.blank?
    out << self.first_name unless self.first_name.blank?
    out.strip
  end

  # @return [String]
  #   The person's full last name including prefix & suffix (von last Jr)
  def full_last_name
    out = ''
    out << self.prefix + ' ' unless self.prefix.blank?
    out << self.last_name unless self.last_name.blank?
    out << ' ' + self.suffix unless self.suffix.blank?
    out.strip
  end

  def is_author?
    self.author_roles.to_a.length > 0
  end

  def is_editor?
    self.editor_roles.to_a.length > 0
  end

  def is_source?
    self.source_roles.to_a.length > 0
  end

  def is_collector?
    self.collector_roles.to_a.length > 0
  end

  def is_determiner?
    self.determiner_roles.to_a.length > 0
  end

  def is_taxon_name_author?
    self.taxon_name_author_roles.to_a.length > 0
  end

  def is_type_designator?
    self.type_designator_roles.to_a.length > 0
  end

  def is_georeferencer?
    self.georeferencer_roles.to_a.length > 0
  end

  # TODO: TEST!
  def self.parser(name_string)
    BibTeX::Entry.new(type: :book, author: name_string).parse_names.to_citeproc['author']
  end

  # TODO: TEST!
  def self.parse_to_people(name_string)
    self.parser(name_string).collect { |n| Person::Unvetted.new(last_name: n['family'], first_name: n['given'], prefix: n['non-dropping-particle']) }
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  protected

  def set_type_if_blank
    self.type = 'Person::Unvetted' if self.type.blank?
  end

  def self.find_for_autocomplete(params)
    where('cached ILIKE ? OR cached ILIKE ? OR cached = ?', "#{params[:term]}%", "%#{params[:term]}%", params[:term])
  end

  def set_cached
    update_column(:cached, self.bibtex_name) if errors.empty? 
  end

end

- (String) last_name

the last/family name

Returns:

  • (String)


34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'app/models/person.rb', line 34

class Person < ApplicationRecord
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::HasPapertrail 
  include Shared::IsData

  # Class constants
  ALTERNATE_VALUES_FOR = [:last_name, :first_name]

  validates_presence_of :last_name, :type
  before_validation :set_type_if_blank

  # after_save :update_bibtex_sources
  after_save :set_cached

  validates :type, inclusion: {in:      ['Person::Vetted', 'Person::Unvetted'],
                               message: "%{value} is not a validly_published type"}

  has_many :roles, dependent: :destroy, inverse_of: :person
  has_many :author_roles, class_name: 'SourceAuthor'
  has_many :editor_roles, class_name: 'SourceEditor'
  has_many :source_roles, class_name: 'SourceSource'
  has_many :collector_roles, class_name: 'Collector'
  has_many :determiner_roles, class_name: 'Determiner'
  has_many :taxon_name_author_roles, class_name: 'TaxonNameAuthor'
  has_many :type_designator_roles, class_name: 'TypeDesignator'
  has_many :georeferencer_roles, class_name: 'Georeferencer'

  # has_many :sources, through: :roles   # TODO: test and confirm dependent

  has_many :authored_sources, through: :author_roles, source: :role_object, source_type: 'Source::Bibtex'
  has_many :edited_sources, through: :editor_roles, source: :role_object, source_type: 'Source::Bibtex'
  has_many :human_sources, through: :source_roles, source: :role_object, source_type: 'Source::Human'
  has_many :collecting_events, through: :collector_roles, source: :role_object, source_type: 'CollectingEvent'
  has_many :taxon_determinations, through: :determiner_roles, source: :role_object, source_type: 'TaxonDetermination'
  has_many :taxon_name_authors, through: :taxon_name_author_roles, source: :role_object, source_type: 'TaxonName'
  has_many :type_material, through: :type_designator_roles, source: :role_object, source_type: 'TypeMaterial'
  has_many :georeferences, through: :georeferencer_roles, source: :role_object, source_type: 'Georeference'

  #scope :named, -> (name) {where(name: name)}
  #scope :named_smith, where(last_name: 'Smith')
  scope :named_smith, -> { where(last_name: 'Smith') }
  #scope :smith_start, -> {where(last_name: start_with?('Smith'))}  # have tried multiple ways to select records where last_name like 'Smith%' without success
  scope :created_before, -> (time) { where('created_at < ?', time) }
  scope :with_role, -> (role) { includes(:roles).where(roles: {type: role}) }
  scope :ordered_by_last_name, -> { order(:last_name) }

  def name
    [self.first_name, self.prefix, self.last_name, self.suffix].compact.join(' ').strip
  end

  # @return [String]
  #   The person's name in BibTeX format (von last, Jr, first)
  def bibtex_name
    out = ''
    out << self.prefix + ' ' unless self.prefix.blank?
    out << self.last_name unless self.last_name.blank?
    out << ', ' unless out.blank? || (self.first_name.blank? && self.suffix.blank?)
    out << self.suffix unless self.suffix.blank?
    out << ', ' unless out.end_with?(', ') || self.first_name.blank? || out.blank?
    out << self.first_name unless self.first_name.blank?
    out.strip
  end

  # @return [String]
  #   The person's full last name including prefix & suffix (von last Jr)
  def full_last_name
    out = ''
    out << self.prefix + ' ' unless self.prefix.blank?
    out << self.last_name unless self.last_name.blank?
    out << ' ' + self.suffix unless self.suffix.blank?
    out.strip
  end

  def is_author?
    self.author_roles.to_a.length > 0
  end

  def is_editor?
    self.editor_roles.to_a.length > 0
  end

  def is_source?
    self.source_roles.to_a.length > 0
  end

  def is_collector?
    self.collector_roles.to_a.length > 0
  end

  def is_determiner?
    self.determiner_roles.to_a.length > 0
  end

  def is_taxon_name_author?
    self.taxon_name_author_roles.to_a.length > 0
  end

  def is_type_designator?
    self.type_designator_roles.to_a.length > 0
  end

  def is_georeferencer?
    self.georeferencer_roles.to_a.length > 0
  end

  # TODO: TEST!
  def self.parser(name_string)
    BibTeX::Entry.new(type: :book, author: name_string).parse_names.to_citeproc['author']
  end

  # TODO: TEST!
  def self.parse_to_people(name_string)
    self.parser(name_string).collect { |n| Person::Unvetted.new(last_name: n['family'], first_name: n['given'], prefix: n['non-dropping-particle']) }
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  protected

  def set_type_if_blank
    self.type = 'Person::Unvetted' if self.type.blank?
  end

  def self.find_for_autocomplete(params)
    where('cached ILIKE ? OR cached ILIKE ? OR cached = ?', "#{params[:term]}%", "%#{params[:term]}%", params[:term])
  end

  def set_cached
    update_column(:cached, self.bibtex_name) if errors.empty? 
  end

end

- (String) suffix

string following the last/family name

Returns:

  • (String)


34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'app/models/person.rb', line 34

class Person < ApplicationRecord
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::HasPapertrail 
  include Shared::IsData

  # Class constants
  ALTERNATE_VALUES_FOR = [:last_name, :first_name]

  validates_presence_of :last_name, :type
  before_validation :set_type_if_blank

  # after_save :update_bibtex_sources
  after_save :set_cached

  validates :type, inclusion: {in:      ['Person::Vetted', 'Person::Unvetted'],
                               message: "%{value} is not a validly_published type"}

  has_many :roles, dependent: :destroy, inverse_of: :person
  has_many :author_roles, class_name: 'SourceAuthor'
  has_many :editor_roles, class_name: 'SourceEditor'
  has_many :source_roles, class_name: 'SourceSource'
  has_many :collector_roles, class_name: 'Collector'
  has_many :determiner_roles, class_name: 'Determiner'
  has_many :taxon_name_author_roles, class_name: 'TaxonNameAuthor'
  has_many :type_designator_roles, class_name: 'TypeDesignator'
  has_many :georeferencer_roles, class_name: 'Georeferencer'

  # has_many :sources, through: :roles   # TODO: test and confirm dependent

  has_many :authored_sources, through: :author_roles, source: :role_object, source_type: 'Source::Bibtex'
  has_many :edited_sources, through: :editor_roles, source: :role_object, source_type: 'Source::Bibtex'
  has_many :human_sources, through: :source_roles, source: :role_object, source_type: 'Source::Human'
  has_many :collecting_events, through: :collector_roles, source: :role_object, source_type: 'CollectingEvent'
  has_many :taxon_determinations, through: :determiner_roles, source: :role_object, source_type: 'TaxonDetermination'
  has_many :taxon_name_authors, through: :taxon_name_author_roles, source: :role_object, source_type: 'TaxonName'
  has_many :type_material, through: :type_designator_roles, source: :role_object, source_type: 'TypeMaterial'
  has_many :georeferences, through: :georeferencer_roles, source: :role_object, source_type: 'Georeference'

  #scope :named, -> (name) {where(name: name)}
  #scope :named_smith, where(last_name: 'Smith')
  scope :named_smith, -> { where(last_name: 'Smith') }
  #scope :smith_start, -> {where(last_name: start_with?('Smith'))}  # have tried multiple ways to select records where last_name like 'Smith%' without success
  scope :created_before, -> (time) { where('created_at < ?', time) }
  scope :with_role, -> (role) { includes(:roles).where(roles: {type: role}) }
  scope :ordered_by_last_name, -> { order(:last_name) }

  def name
    [self.first_name, self.prefix, self.last_name, self.suffix].compact.join(' ').strip
  end

  # @return [String]
  #   The person's name in BibTeX format (von last, Jr, first)
  def bibtex_name
    out = ''
    out << self.prefix + ' ' unless self.prefix.blank?
    out << self.last_name unless self.last_name.blank?
    out << ', ' unless out.blank? || (self.first_name.blank? && self.suffix.blank?)
    out << self.suffix unless self.suffix.blank?
    out << ', ' unless out.end_with?(', ') || self.first_name.blank? || out.blank?
    out << self.first_name unless self.first_name.blank?
    out.strip
  end

  # @return [String]
  #   The person's full last name including prefix & suffix (von last Jr)
  def full_last_name
    out = ''
    out << self.prefix + ' ' unless self.prefix.blank?
    out << self.last_name unless self.last_name.blank?
    out << ' ' + self.suffix unless self.suffix.blank?
    out.strip
  end

  def is_author?
    self.author_roles.to_a.length > 0
  end

  def is_editor?
    self.editor_roles.to_a.length > 0
  end

  def is_source?
    self.source_roles.to_a.length > 0
  end

  def is_collector?
    self.collector_roles.to_a.length > 0
  end

  def is_determiner?
    self.determiner_roles.to_a.length > 0
  end

  def is_taxon_name_author?
    self.taxon_name_author_roles.to_a.length > 0
  end

  def is_type_designator?
    self.type_designator_roles.to_a.length > 0
  end

  def is_georeferencer?
    self.georeferencer_roles.to_a.length > 0
  end

  # TODO: TEST!
  def self.parser(name_string)
    BibTeX::Entry.new(type: :book, author: name_string).parse_names.to_citeproc['author']
  end

  # TODO: TEST!
  def self.parse_to_people(name_string)
    self.parser(name_string).collect { |n| Person::Unvetted.new(last_name: n['family'], first_name: n['given'], prefix: n['non-dropping-particle']) }
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  protected

  def set_type_if_blank
    self.type = 'Person::Unvetted' if self.type.blank?
  end

  def self.find_for_autocomplete(params)
    where('cached ILIKE ? OR cached ILIKE ? OR cached = ?', "#{params[:term]}%", "%#{params[:term]}%", params[:term])
  end

  def set_cached
    update_column(:cached, self.bibtex_name) if errors.empty? 
  end

end

- (String) type

Person::Vetted or Person::Unvetted

Returns:

  • (String)


34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'app/models/person.rb', line 34

class Person < ApplicationRecord
  include Housekeeping::Users
  include Housekeeping::Timestamps
  include Shared::AlternateValues
  include Shared::DataAttributes
  include Shared::Identifiable
  include Shared::Notable
  include Shared::SharedAcrossProjects
  include Shared::HasPapertrail 
  include Shared::IsData

  # Class constants
  ALTERNATE_VALUES_FOR = [:last_name, :first_name]

  validates_presence_of :last_name, :type
  before_validation :set_type_if_blank

  # after_save :update_bibtex_sources
  after_save :set_cached

  validates :type, inclusion: {in:      ['Person::Vetted', 'Person::Unvetted'],
                               message: "%{value} is not a validly_published type"}

  has_many :roles, dependent: :destroy, inverse_of: :person
  has_many :author_roles, class_name: 'SourceAuthor'
  has_many :editor_roles, class_name: 'SourceEditor'
  has_many :source_roles, class_name: 'SourceSource'
  has_many :collector_roles, class_name: 'Collector'
  has_many :determiner_roles, class_name: 'Determiner'
  has_many :taxon_name_author_roles, class_name: 'TaxonNameAuthor'
  has_many :type_designator_roles, class_name: 'TypeDesignator'
  has_many :georeferencer_roles, class_name: 'Georeferencer'

  # has_many :sources, through: :roles   # TODO: test and confirm dependent

  has_many :authored_sources, through: :author_roles, source: :role_object, source_type: 'Source::Bibtex'
  has_many :edited_sources, through: :editor_roles, source: :role_object, source_type: 'Source::Bibtex'
  has_many :human_sources, through: :source_roles, source: :role_object, source_type: 'Source::Human'
  has_many :collecting_events, through: :collector_roles, source: :role_object, source_type: 'CollectingEvent'
  has_many :taxon_determinations, through: :determiner_roles, source: :role_object, source_type: 'TaxonDetermination'
  has_many :taxon_name_authors, through: :taxon_name_author_roles, source: :role_object, source_type: 'TaxonName'
  has_many :type_material, through: :type_designator_roles, source: :role_object, source_type: 'TypeMaterial'
  has_many :georeferences, through: :georeferencer_roles, source: :role_object, source_type: 'Georeference'

  #scope :named, -> (name) {where(name: name)}
  #scope :named_smith, where(last_name: 'Smith')
  scope :named_smith, -> { where(last_name: 'Smith') }
  #scope :smith_start, -> {where(last_name: start_with?('Smith'))}  # have tried multiple ways to select records where last_name like 'Smith%' without success
  scope :created_before, -> (time) { where('created_at < ?', time) }
  scope :with_role, -> (role) { includes(:roles).where(roles: {type: role}) }
  scope :ordered_by_last_name, -> { order(:last_name) }

  def name
    [self.first_name, self.prefix, self.last_name, self.suffix].compact.join(' ').strip
  end

  # @return [String]
  #   The person's name in BibTeX format (von last, Jr, first)
  def bibtex_name
    out = ''
    out << self.prefix + ' ' unless self.prefix.blank?
    out << self.last_name unless self.last_name.blank?
    out << ', ' unless out.blank? || (self.first_name.blank? && self.suffix.blank?)
    out << self.suffix unless self.suffix.blank?
    out << ', ' unless out.end_with?(', ') || self.first_name.blank? || out.blank?
    out << self.first_name unless self.first_name.blank?
    out.strip
  end

  # @return [String]
  #   The person's full last name including prefix & suffix (von last Jr)
  def full_last_name
    out = ''
    out << self.prefix + ' ' unless self.prefix.blank?
    out << self.last_name unless self.last_name.blank?
    out << ' ' + self.suffix unless self.suffix.blank?
    out.strip
  end

  def is_author?
    self.author_roles.to_a.length > 0
  end

  def is_editor?
    self.editor_roles.to_a.length > 0
  end

  def is_source?
    self.source_roles.to_a.length > 0
  end

  def is_collector?
    self.collector_roles.to_a.length > 0
  end

  def is_determiner?
    self.determiner_roles.to_a.length > 0
  end

  def is_taxon_name_author?
    self.taxon_name_author_roles.to_a.length > 0
  end

  def is_type_designator?
    self.type_designator_roles.to_a.length > 0
  end

  def is_georeferencer?
    self.georeferencer_roles.to_a.length > 0
  end

  # TODO: TEST!
  def self.parser(name_string)
    BibTeX::Entry.new(type: :book, author: name_string).parse_names.to_citeproc['author']
  end

  # TODO: TEST!
  def self.parse_to_people(name_string)
    self.parser(name_string).collect { |n| Person::Unvetted.new(last_name: n['family'], first_name: n['given'], prefix: n['non-dropping-particle']) }
  end

  def self.generate_download(scope)
    CSV.generate do |csv|
      csv << column_names
      scope.order(id: :asc).find_each do |o|
        csv << o.attributes.values_at(*column_names).collect { |i|
          i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
        }
      end
    end
  end

  protected

  def set_type_if_blank
    self.type = 'Person::Unvetted' if self.type.blank?
  end

  def self.find_for_autocomplete(params)
    where('cached ILIKE ? OR cached ILIKE ? OR cached = ?', "#{params[:term]}%", "%#{params[:term]}%", params[:term])
  end

  def set_cached
    update_column(:cached, self.bibtex_name) if errors.empty? 
  end

end

Class Method Details

+ (Object) find_for_autocomplete(params) (protected)



172
173
174
# File 'app/models/person.rb', line 172

def self.find_for_autocomplete(params)
  where('cached ILIKE ? OR cached ILIKE ? OR cached = ?', "#{params[:term]}%", "%#{params[:term]}%", params[:term])
end

+ (Object) generate_download(scope)



155
156
157
158
159
160
161
162
163
164
# File 'app/models/person.rb', line 155

def self.generate_download(scope)
  CSV.generate do |csv|
    csv << column_names
    scope.order(id: :asc).find_each do |o|
      csv << o.attributes.values_at(*column_names).collect { |i|
        i.to_s.gsub(/\n/, '\n').gsub(/\t/, '\t')
      }
    end
  end
end

+ (Object) parse_to_people(name_string)

TODO: TEST!



151
152
153
# File 'app/models/person.rb', line 151

def self.parse_to_people(name_string)
  self.parser(name_string).collect { |n| Person::Unvetted.new(last_name: n['family'], first_name: n['given'], prefix: n['non-dropping-particle']) }
end

+ (Object) parser(name_string)

TODO: TEST!



146
147
148
# File 'app/models/person.rb', line 146

def self.parser(name_string)
  BibTeX::Entry.new(type: :book, author: name_string).parse_names.to_citeproc['author']
end

Instance Method Details

- (String) bibtex_name

Returns The person's name in BibTeX format (von last, Jr, first)

Returns:

  • (String)

    The person's name in BibTeX format (von last, Jr, first)



92
93
94
95
96
97
98
99
100
101
# File 'app/models/person.rb', line 92

def bibtex_name
  out = ''
  out << self.prefix + ' ' unless self.prefix.blank?
  out << self.last_name unless self.last_name.blank?
  out << ', ' unless out.blank? || (self.first_name.blank? && self.suffix.blank?)
  out << self.suffix unless self.suffix.blank?
  out << ', ' unless out.end_with?(', ') || self.first_name.blank? || out.blank?
  out << self.first_name unless self.first_name.blank?
  out.strip
end

- (String) full_last_name

Returns The person's full last name including prefix & suffix (von last Jr)

Returns:

  • (String)

    The person's full last name including prefix & suffix (von last Jr)



105
106
107
108
109
110
111
# File 'app/models/person.rb', line 105

def full_last_name
  out = ''
  out << self.prefix + ' ' unless self.prefix.blank?
  out << self.last_name unless self.last_name.blank?
  out << ' ' + self.suffix unless self.suffix.blank?
  out.strip
end

- (Boolean) is_author?

Returns:

  • (Boolean)


113
114
115
# File 'app/models/person.rb', line 113

def is_author?
  self.author_roles.to_a.length > 0
end

- (Boolean) is_collector?

Returns:

  • (Boolean)


125
126
127
# File 'app/models/person.rb', line 125

def is_collector?
  self.collector_roles.to_a.length > 0
end

- (Boolean) is_determiner?

Returns:

  • (Boolean)


129
130
131
# File 'app/models/person.rb', line 129

def is_determiner?
  self.determiner_roles.to_a.length > 0
end

- (Boolean) is_editor?

Returns:

  • (Boolean)


117
118
119
# File 'app/models/person.rb', line 117

def is_editor?
  self.editor_roles.to_a.length > 0
end

- (Boolean) is_georeferencer?

Returns:

  • (Boolean)


141
142
143
# File 'app/models/person.rb', line 141

def is_georeferencer?
  self.georeferencer_roles.to_a.length > 0
end

- (Boolean) is_source?

Returns:

  • (Boolean)


121
122
123
# File 'app/models/person.rb', line 121

def is_source?
  self.source_roles.to_a.length > 0
end

- (Boolean) is_taxon_name_author?

Returns:

  • (Boolean)


133
134
135
# File 'app/models/person.rb', line 133

def is_taxon_name_author?
  self.taxon_name_author_roles.to_a.length > 0
end

- (Boolean) is_type_designator?

Returns:

  • (Boolean)


137
138
139
# File 'app/models/person.rb', line 137

def is_type_designator?
  self.type_designator_roles.to_a.length > 0
end

- (Object) name



86
87
88
# File 'app/models/person.rb', line 86

def name
  [self.first_name, self.prefix, self.last_name, self.suffix].compact.join(' ').strip
end

- (Object) set_cached (protected)



176
177
178
# File 'app/models/person.rb', line 176

def set_cached
  update_column(:cached, self.bibtex_name) if errors.empty? 
end

- (Object) set_type_if_blank (protected)



168
169
170
# File 'app/models/person.rb', line 168

def set_type_if_blank
  self.type = 'Person::Unvetted' if self.type.blank?
end