Class: Citation

Inherits:
ApplicationRecord show all
Includes:
Housekeeping, Shared::IsData, Shared::Notes, Shared::PolymorphicAnnotator, Shared::Tags
Defined in:
app/models/citation.rb

Overview

A Citation is an assertion that the subject (i.e. citation object/record/data instance), or some attribute of it, was referenced or originated in a Source.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Housekeeping

#has_polymorphic_relationship?

Instance Attribute Details

#citation_object_idInteger

Returns Rails STI, the id of the object being cited

Returns:

  • (Integer)

    Rails STI, the id of the object being cited



29
30
31
32
33
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
# File 'app/models/citation.rb', line 29

class Citation < ApplicationRecord

  # Citations do not have Confidence or DataAttribute.

  include Housekeeping
  include Shared::Notes
  include Shared::Tags
  include Shared::IsData
  include Shared::PolymorphicAnnotator

  attr_accessor :no_cached

  polymorphic_annotates('citation_object')

  belongs_to :source, inverse_of: :citations

  has_many :citation_topics, inverse_of: :citation, dependent: :destroy
  has_many :topics, through: :citation_topics, inverse_of: :citations
  has_many :documents, through: :source

  # TODO: This is wrong, should be source
  validates_presence_of  :source_id

  validates_uniqueness_of :source_id, scope: [:citation_object_id, :citation_object_type, :pages]

  validates_uniqueness_of :is_original, scope: [:citation_object_type, :citation_object_id], message: 'origin can only be assigned once', allow_nil: true, if: :is_original?

  accepts_nested_attributes_for :citation_topics, allow_destroy: true, reject_if: :reject_citation_topics
  accepts_nested_attributes_for :topics, allow_destroy: true, reject_if: :reject_topic

  before_destroy :prevent_if_required

  after_create :add_source_to_project
  after_save :update_related_cached_values, if: :is_original?

  after_save :set_cached_names_for_taxon_names, unless: -> {self.no_cached}
  after_destroy :set_cached_names_for_taxon_names, unless: -> {self.no_cached}


  # TODO: deprecate
  # @return [Scope of matching sources]
  def self.find_for_autocomplete(params)
    term = params['term']
    ending = term + '%'
    wrapped = '%' + term + '%'
    joins(:source).where('sources.cached ILIKE ? OR sources.cached ILIKE ? OR citation_object_type LIKE ?', ending, wrapped, ending).with_project_id(params[:project_id])
  end

  # @return [Boolean]
  #   true if is_original is checked, false if nil/false
  def is_original?
    is_original ? true : false
  end

  # @return [String, nil]
  #    the first integer in the string, as a string
  def first_page
    /(?<i>\d+)/ =~ pages
    i 
  end

  # @return [Integer, nil]
  #    if a target document
  def target_document_page
    target_document.try(:pdf_page_for, first_page).try(:first)
  end

  # @return [Document, nil]
  def target_document
    documents.order('documentation.position').first
  end

  protected

  def add_source_to_project
    if !ProjectSource.where(source: source).any?
      ProjectSource.create(project: project, source: source)
    end
    true
  end

  def reject_citation_topics(attributed)
    attributes['id'].blank? && attributed['topic_id'].blank? && attributed['topic'].blank? && attributed['topic_attributes'].blank?
  end

  def reject_topic(attributed)
    attributed['name'].blank? || attributed['definition'].blank?
  end

  def update_related_cached_values
    if citation_object_type == 'TaxonName'
      citation_object.update_attribute(:cached_author_year, citation_object.get_author_and_year)
    end
    true
  end

  # TODO: modify for asserted distributions and other origin style relationships
  def prevent_if_required
    if !marked_for_destruction? && !new_record? && citation_object.requires_citation? && citation_object.citations.reload.count == 1
      errors.add(:base, 'at least one citation is required')
      throw :abort
    end
  end

  def set_cached_names_for_taxon_names
    if citation_object_type == 'TaxonNameRelationship' && TAXON_NAME_RELATIONSHIP_NAMES_INVALID.include?(citation_object.try(:type_name))
      begin
        TaxonNameRelationship.transaction do
          t = citation_object.subject_taxon_name
          vn = t.get_valid_taxon_name

          t.update_columns(
              cached: t.get_full_name,
              cached_html: t.get_full_name_html,
              cached_valid_taxon_name_id: vn.id)
          t.combination_list_self.each do |c|
            c.update_column(:cached_valid_taxon_name_id, vn.id)
          end

          vn.list_of_invalid_taxon_names.each do |s|
            s.update_column(:cached_valid_taxon_name_id, vn.id)
            s.combination_list_self.each do |c|
              c.update_column(:cached_valid_taxon_name_id, vn.id)
            end
          end
        end
      rescue ActiveRecord::RecordInvalid
        raise
      end
      false
    end
  end

end

#citation_object_typeString

Returns Rails STI, the class of the object being cited

Returns:

  • (String)

    Rails STI, the class of the object being cited



29
30
31
32
33
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
# File 'app/models/citation.rb', line 29

class Citation < ApplicationRecord

  # Citations do not have Confidence or DataAttribute.

  include Housekeeping
  include Shared::Notes
  include Shared::Tags
  include Shared::IsData
  include Shared::PolymorphicAnnotator

  attr_accessor :no_cached

  polymorphic_annotates('citation_object')

  belongs_to :source, inverse_of: :citations

  has_many :citation_topics, inverse_of: :citation, dependent: :destroy
  has_many :topics, through: :citation_topics, inverse_of: :citations
  has_many :documents, through: :source

  # TODO: This is wrong, should be source
  validates_presence_of  :source_id

  validates_uniqueness_of :source_id, scope: [:citation_object_id, :citation_object_type, :pages]

  validates_uniqueness_of :is_original, scope: [:citation_object_type, :citation_object_id], message: 'origin can only be assigned once', allow_nil: true, if: :is_original?

  accepts_nested_attributes_for :citation_topics, allow_destroy: true, reject_if: :reject_citation_topics
  accepts_nested_attributes_for :topics, allow_destroy: true, reject_if: :reject_topic

  before_destroy :prevent_if_required

  after_create :add_source_to_project
  after_save :update_related_cached_values, if: :is_original?

  after_save :set_cached_names_for_taxon_names, unless: -> {self.no_cached}
  after_destroy :set_cached_names_for_taxon_names, unless: -> {self.no_cached}


  # TODO: deprecate
  # @return [Scope of matching sources]
  def self.find_for_autocomplete(params)
    term = params['term']
    ending = term + '%'
    wrapped = '%' + term + '%'
    joins(:source).where('sources.cached ILIKE ? OR sources.cached ILIKE ? OR citation_object_type LIKE ?', ending, wrapped, ending).with_project_id(params[:project_id])
  end

  # @return [Boolean]
  #   true if is_original is checked, false if nil/false
  def is_original?
    is_original ? true : false
  end

  # @return [String, nil]
  #    the first integer in the string, as a string
  def first_page
    /(?<i>\d+)/ =~ pages
    i 
  end

  # @return [Integer, nil]
  #    if a target document
  def target_document_page
    target_document.try(:pdf_page_for, first_page).try(:first)
  end

  # @return [Document, nil]
  def target_document
    documents.order('documentation.position').first
  end

  protected

  def add_source_to_project
    if !ProjectSource.where(source: source).any?
      ProjectSource.create(project: project, source: source)
    end
    true
  end

  def reject_citation_topics(attributed)
    attributes['id'].blank? && attributed['topic_id'].blank? && attributed['topic'].blank? && attributed['topic_attributes'].blank?
  end

  def reject_topic(attributed)
    attributed['name'].blank? || attributed['definition'].blank?
  end

  def update_related_cached_values
    if citation_object_type == 'TaxonName'
      citation_object.update_attribute(:cached_author_year, citation_object.get_author_and_year)
    end
    true
  end

  # TODO: modify for asserted distributions and other origin style relationships
  def prevent_if_required
    if !marked_for_destruction? && !new_record? && citation_object.requires_citation? && citation_object.citations.reload.count == 1
      errors.add(:base, 'at least one citation is required')
      throw :abort
    end
  end

  def set_cached_names_for_taxon_names
    if citation_object_type == 'TaxonNameRelationship' && TAXON_NAME_RELATIONSHIP_NAMES_INVALID.include?(citation_object.try(:type_name))
      begin
        TaxonNameRelationship.transaction do
          t = citation_object.subject_taxon_name
          vn = t.get_valid_taxon_name

          t.update_columns(
              cached: t.get_full_name,
              cached_html: t.get_full_name_html,
              cached_valid_taxon_name_id: vn.id)
          t.combination_list_self.each do |c|
            c.update_column(:cached_valid_taxon_name_id, vn.id)
          end

          vn.list_of_invalid_taxon_names.each do |s|
            s.update_column(:cached_valid_taxon_name_id, vn.id)
            s.combination_list_self.each do |c|
              c.update_column(:cached_valid_taxon_name_id, vn.id)
            end
          end
        end
      rescue ActiveRecord::RecordInvalid
        raise
      end
      false
    end
  end

end

#is_originalBoolean

Returns is this the first citation in which the data were observed?

Returns:

  • (Boolean)

    is this the first citation in which the data were observed?



29
30
31
32
33
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
# File 'app/models/citation.rb', line 29

class Citation < ApplicationRecord

  # Citations do not have Confidence or DataAttribute.

  include Housekeeping
  include Shared::Notes
  include Shared::Tags
  include Shared::IsData
  include Shared::PolymorphicAnnotator

  attr_accessor :no_cached

  polymorphic_annotates('citation_object')

  belongs_to :source, inverse_of: :citations

  has_many :citation_topics, inverse_of: :citation, dependent: :destroy
  has_many :topics, through: :citation_topics, inverse_of: :citations
  has_many :documents, through: :source

  # TODO: This is wrong, should be source
  validates_presence_of  :source_id

  validates_uniqueness_of :source_id, scope: [:citation_object_id, :citation_object_type, :pages]

  validates_uniqueness_of :is_original, scope: [:citation_object_type, :citation_object_id], message: 'origin can only be assigned once', allow_nil: true, if: :is_original?

  accepts_nested_attributes_for :citation_topics, allow_destroy: true, reject_if: :reject_citation_topics
  accepts_nested_attributes_for :topics, allow_destroy: true, reject_if: :reject_topic

  before_destroy :prevent_if_required

  after_create :add_source_to_project
  after_save :update_related_cached_values, if: :is_original?

  after_save :set_cached_names_for_taxon_names, unless: -> {self.no_cached}
  after_destroy :set_cached_names_for_taxon_names, unless: -> {self.no_cached}


  # TODO: deprecate
  # @return [Scope of matching sources]
  def self.find_for_autocomplete(params)
    term = params['term']
    ending = term + '%'
    wrapped = '%' + term + '%'
    joins(:source).where('sources.cached ILIKE ? OR sources.cached ILIKE ? OR citation_object_type LIKE ?', ending, wrapped, ending).with_project_id(params[:project_id])
  end

  # @return [Boolean]
  #   true if is_original is checked, false if nil/false
  def is_original?
    is_original ? true : false
  end

  # @return [String, nil]
  #    the first integer in the string, as a string
  def first_page
    /(?<i>\d+)/ =~ pages
    i 
  end

  # @return [Integer, nil]
  #    if a target document
  def target_document_page
    target_document.try(:pdf_page_for, first_page).try(:first)
  end

  # @return [Document, nil]
  def target_document
    documents.order('documentation.position').first
  end

  protected

  def add_source_to_project
    if !ProjectSource.where(source: source).any?
      ProjectSource.create(project: project, source: source)
    end
    true
  end

  def reject_citation_topics(attributed)
    attributes['id'].blank? && attributed['topic_id'].blank? && attributed['topic'].blank? && attributed['topic_attributes'].blank?
  end

  def reject_topic(attributed)
    attributed['name'].blank? || attributed['definition'].blank?
  end

  def update_related_cached_values
    if citation_object_type == 'TaxonName'
      citation_object.update_attribute(:cached_author_year, citation_object.get_author_and_year)
    end
    true
  end

  # TODO: modify for asserted distributions and other origin style relationships
  def prevent_if_required
    if !marked_for_destruction? && !new_record? && citation_object.requires_citation? && citation_object.citations.reload.count == 1
      errors.add(:base, 'at least one citation is required')
      throw :abort
    end
  end

  def set_cached_names_for_taxon_names
    if citation_object_type == 'TaxonNameRelationship' && TAXON_NAME_RELATIONSHIP_NAMES_INVALID.include?(citation_object.try(:type_name))
      begin
        TaxonNameRelationship.transaction do
          t = citation_object.subject_taxon_name
          vn = t.get_valid_taxon_name

          t.update_columns(
              cached: t.get_full_name,
              cached_html: t.get_full_name_html,
              cached_valid_taxon_name_id: vn.id)
          t.combination_list_self.each do |c|
            c.update_column(:cached_valid_taxon_name_id, vn.id)
          end

          vn.list_of_invalid_taxon_names.each do |s|
            s.update_column(:cached_valid_taxon_name_id, vn.id)
            s.combination_list_self.each do |c|
              c.update_column(:cached_valid_taxon_name_id, vn.id)
            end
          end
        end
      rescue ActiveRecord::RecordInvalid
        raise
      end
      false
    end
  end

end

#no_cachedObject

Returns the value of attribute no_cached



39
40
41
# File 'app/models/citation.rb', line 39

def no_cached
  @no_cached
end

#pagesString?

Returns a specific location/localization for the data in the Source, if you lead with an integer seperated by space or punctation that integer will be returned as the “first” page and usable in direct linkouts to Documents if available

Returns:

  • (String, nil)

    a specific location/localization for the data in the Source, if you lead with an integer seperated by space or punctation that integer will be returned as the “first” page and usable in direct linkouts to Documents if available



29
30
31
32
33
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
# File 'app/models/citation.rb', line 29

class Citation < ApplicationRecord

  # Citations do not have Confidence or DataAttribute.

  include Housekeeping
  include Shared::Notes
  include Shared::Tags
  include Shared::IsData
  include Shared::PolymorphicAnnotator

  attr_accessor :no_cached

  polymorphic_annotates('citation_object')

  belongs_to :source, inverse_of: :citations

  has_many :citation_topics, inverse_of: :citation, dependent: :destroy
  has_many :topics, through: :citation_topics, inverse_of: :citations
  has_many :documents, through: :source

  # TODO: This is wrong, should be source
  validates_presence_of  :source_id

  validates_uniqueness_of :source_id, scope: [:citation_object_id, :citation_object_type, :pages]

  validates_uniqueness_of :is_original, scope: [:citation_object_type, :citation_object_id], message: 'origin can only be assigned once', allow_nil: true, if: :is_original?

  accepts_nested_attributes_for :citation_topics, allow_destroy: true, reject_if: :reject_citation_topics
  accepts_nested_attributes_for :topics, allow_destroy: true, reject_if: :reject_topic

  before_destroy :prevent_if_required

  after_create :add_source_to_project
  after_save :update_related_cached_values, if: :is_original?

  after_save :set_cached_names_for_taxon_names, unless: -> {self.no_cached}
  after_destroy :set_cached_names_for_taxon_names, unless: -> {self.no_cached}


  # TODO: deprecate
  # @return [Scope of matching sources]
  def self.find_for_autocomplete(params)
    term = params['term']
    ending = term + '%'
    wrapped = '%' + term + '%'
    joins(:source).where('sources.cached ILIKE ? OR sources.cached ILIKE ? OR citation_object_type LIKE ?', ending, wrapped, ending).with_project_id(params[:project_id])
  end

  # @return [Boolean]
  #   true if is_original is checked, false if nil/false
  def is_original?
    is_original ? true : false
  end

  # @return [String, nil]
  #    the first integer in the string, as a string
  def first_page
    /(?<i>\d+)/ =~ pages
    i 
  end

  # @return [Integer, nil]
  #    if a target document
  def target_document_page
    target_document.try(:pdf_page_for, first_page).try(:first)
  end

  # @return [Document, nil]
  def target_document
    documents.order('documentation.position').first
  end

  protected

  def add_source_to_project
    if !ProjectSource.where(source: source).any?
      ProjectSource.create(project: project, source: source)
    end
    true
  end

  def reject_citation_topics(attributed)
    attributes['id'].blank? && attributed['topic_id'].blank? && attributed['topic'].blank? && attributed['topic_attributes'].blank?
  end

  def reject_topic(attributed)
    attributed['name'].blank? || attributed['definition'].blank?
  end

  def update_related_cached_values
    if citation_object_type == 'TaxonName'
      citation_object.update_attribute(:cached_author_year, citation_object.get_author_and_year)
    end
    true
  end

  # TODO: modify for asserted distributions and other origin style relationships
  def prevent_if_required
    if !marked_for_destruction? && !new_record? && citation_object.requires_citation? && citation_object.citations.reload.count == 1
      errors.add(:base, 'at least one citation is required')
      throw :abort
    end
  end

  def set_cached_names_for_taxon_names
    if citation_object_type == 'TaxonNameRelationship' && TAXON_NAME_RELATIONSHIP_NAMES_INVALID.include?(citation_object.try(:type_name))
      begin
        TaxonNameRelationship.transaction do
          t = citation_object.subject_taxon_name
          vn = t.get_valid_taxon_name

          t.update_columns(
              cached: t.get_full_name,
              cached_html: t.get_full_name_html,
              cached_valid_taxon_name_id: vn.id)
          t.combination_list_self.each do |c|
            c.update_column(:cached_valid_taxon_name_id, vn.id)
          end

          vn.list_of_invalid_taxon_names.each do |s|
            s.update_column(:cached_valid_taxon_name_id, vn.id)
            s.combination_list_self.each do |c|
              c.update_column(:cached_valid_taxon_name_id, vn.id)
            end
          end
        end
      rescue ActiveRecord::RecordInvalid
        raise
      end
      false
    end
  end

end

#project_idInteger

the project ID

Returns:

  • (Integer)


29
30
31
32
33
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
# File 'app/models/citation.rb', line 29

class Citation < ApplicationRecord

  # Citations do not have Confidence or DataAttribute.

  include Housekeeping
  include Shared::Notes
  include Shared::Tags
  include Shared::IsData
  include Shared::PolymorphicAnnotator

  attr_accessor :no_cached

  polymorphic_annotates('citation_object')

  belongs_to :source, inverse_of: :citations

  has_many :citation_topics, inverse_of: :citation, dependent: :destroy
  has_many :topics, through: :citation_topics, inverse_of: :citations
  has_many :documents, through: :source

  # TODO: This is wrong, should be source
  validates_presence_of  :source_id

  validates_uniqueness_of :source_id, scope: [:citation_object_id, :citation_object_type, :pages]

  validates_uniqueness_of :is_original, scope: [:citation_object_type, :citation_object_id], message: 'origin can only be assigned once', allow_nil: true, if: :is_original?

  accepts_nested_attributes_for :citation_topics, allow_destroy: true, reject_if: :reject_citation_topics
  accepts_nested_attributes_for :topics, allow_destroy: true, reject_if: :reject_topic

  before_destroy :prevent_if_required

  after_create :add_source_to_project
  after_save :update_related_cached_values, if: :is_original?

  after_save :set_cached_names_for_taxon_names, unless: -> {self.no_cached}
  after_destroy :set_cached_names_for_taxon_names, unless: -> {self.no_cached}


  # TODO: deprecate
  # @return [Scope of matching sources]
  def self.find_for_autocomplete(params)
    term = params['term']
    ending = term + '%'
    wrapped = '%' + term + '%'
    joins(:source).where('sources.cached ILIKE ? OR sources.cached ILIKE ? OR citation_object_type LIKE ?', ending, wrapped, ending).with_project_id(params[:project_id])
  end

  # @return [Boolean]
  #   true if is_original is checked, false if nil/false
  def is_original?
    is_original ? true : false
  end

  # @return [String, nil]
  #    the first integer in the string, as a string
  def first_page
    /(?<i>\d+)/ =~ pages
    i 
  end

  # @return [Integer, nil]
  #    if a target document
  def target_document_page
    target_document.try(:pdf_page_for, first_page).try(:first)
  end

  # @return [Document, nil]
  def target_document
    documents.order('documentation.position').first
  end

  protected

  def add_source_to_project
    if !ProjectSource.where(source: source).any?
      ProjectSource.create(project: project, source: source)
    end
    true
  end

  def reject_citation_topics(attributed)
    attributes['id'].blank? && attributed['topic_id'].blank? && attributed['topic'].blank? && attributed['topic_attributes'].blank?
  end

  def reject_topic(attributed)
    attributed['name'].blank? || attributed['definition'].blank?
  end

  def update_related_cached_values
    if citation_object_type == 'TaxonName'
      citation_object.update_attribute(:cached_author_year, citation_object.get_author_and_year)
    end
    true
  end

  # TODO: modify for asserted distributions and other origin style relationships
  def prevent_if_required
    if !marked_for_destruction? && !new_record? && citation_object.requires_citation? && citation_object.citations.reload.count == 1
      errors.add(:base, 'at least one citation is required')
      throw :abort
    end
  end

  def set_cached_names_for_taxon_names
    if citation_object_type == 'TaxonNameRelationship' && TAXON_NAME_RELATIONSHIP_NAMES_INVALID.include?(citation_object.try(:type_name))
      begin
        TaxonNameRelationship.transaction do
          t = citation_object.subject_taxon_name
          vn = t.get_valid_taxon_name

          t.update_columns(
              cached: t.get_full_name,
              cached_html: t.get_full_name_html,
              cached_valid_taxon_name_id: vn.id)
          t.combination_list_self.each do |c|
            c.update_column(:cached_valid_taxon_name_id, vn.id)
          end

          vn.list_of_invalid_taxon_names.each do |s|
            s.update_column(:cached_valid_taxon_name_id, vn.id)
            s.combination_list_self.each do |c|
              c.update_column(:cached_valid_taxon_name_id, vn.id)
            end
          end
        end
      rescue ActiveRecord::RecordInvalid
        raise
      end
      false
    end
  end

end

#source_idInteger

the source ID

Returns:

  • (Integer)


29
30
31
32
33
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
# File 'app/models/citation.rb', line 29

class Citation < ApplicationRecord

  # Citations do not have Confidence or DataAttribute.

  include Housekeeping
  include Shared::Notes
  include Shared::Tags
  include Shared::IsData
  include Shared::PolymorphicAnnotator

  attr_accessor :no_cached

  polymorphic_annotates('citation_object')

  belongs_to :source, inverse_of: :citations

  has_many :citation_topics, inverse_of: :citation, dependent: :destroy
  has_many :topics, through: :citation_topics, inverse_of: :citations
  has_many :documents, through: :source

  # TODO: This is wrong, should be source
  validates_presence_of  :source_id

  validates_uniqueness_of :source_id, scope: [:citation_object_id, :citation_object_type, :pages]

  validates_uniqueness_of :is_original, scope: [:citation_object_type, :citation_object_id], message: 'origin can only be assigned once', allow_nil: true, if: :is_original?

  accepts_nested_attributes_for :citation_topics, allow_destroy: true, reject_if: :reject_citation_topics
  accepts_nested_attributes_for :topics, allow_destroy: true, reject_if: :reject_topic

  before_destroy :prevent_if_required

  after_create :add_source_to_project
  after_save :update_related_cached_values, if: :is_original?

  after_save :set_cached_names_for_taxon_names, unless: -> {self.no_cached}
  after_destroy :set_cached_names_for_taxon_names, unless: -> {self.no_cached}


  # TODO: deprecate
  # @return [Scope of matching sources]
  def self.find_for_autocomplete(params)
    term = params['term']
    ending = term + '%'
    wrapped = '%' + term + '%'
    joins(:source).where('sources.cached ILIKE ? OR sources.cached ILIKE ? OR citation_object_type LIKE ?', ending, wrapped, ending).with_project_id(params[:project_id])
  end

  # @return [Boolean]
  #   true if is_original is checked, false if nil/false
  def is_original?
    is_original ? true : false
  end

  # @return [String, nil]
  #    the first integer in the string, as a string
  def first_page
    /(?<i>\d+)/ =~ pages
    i 
  end

  # @return [Integer, nil]
  #    if a target document
  def target_document_page
    target_document.try(:pdf_page_for, first_page).try(:first)
  end

  # @return [Document, nil]
  def target_document
    documents.order('documentation.position').first
  end

  protected

  def add_source_to_project
    if !ProjectSource.where(source: source).any?
      ProjectSource.create(project: project, source: source)
    end
    true
  end

  def reject_citation_topics(attributed)
    attributes['id'].blank? && attributed['topic_id'].blank? && attributed['topic'].blank? && attributed['topic_attributes'].blank?
  end

  def reject_topic(attributed)
    attributed['name'].blank? || attributed['definition'].blank?
  end

  def update_related_cached_values
    if citation_object_type == 'TaxonName'
      citation_object.update_attribute(:cached_author_year, citation_object.get_author_and_year)
    end
    true
  end

  # TODO: modify for asserted distributions and other origin style relationships
  def prevent_if_required
    if !marked_for_destruction? && !new_record? && citation_object.requires_citation? && citation_object.citations.reload.count == 1
      errors.add(:base, 'at least one citation is required')
      throw :abort
    end
  end

  def set_cached_names_for_taxon_names
    if citation_object_type == 'TaxonNameRelationship' && TAXON_NAME_RELATIONSHIP_NAMES_INVALID.include?(citation_object.try(:type_name))
      begin
        TaxonNameRelationship.transaction do
          t = citation_object.subject_taxon_name
          vn = t.get_valid_taxon_name

          t.update_columns(
              cached: t.get_full_name,
              cached_html: t.get_full_name_html,
              cached_valid_taxon_name_id: vn.id)
          t.combination_list_self.each do |c|
            c.update_column(:cached_valid_taxon_name_id, vn.id)
          end

          vn.list_of_invalid_taxon_names.each do |s|
            s.update_column(:cached_valid_taxon_name_id, vn.id)
            s.combination_list_self.each do |c|
              c.update_column(:cached_valid_taxon_name_id, vn.id)
            end
          end
        end
      rescue ActiveRecord::RecordInvalid
        raise
      end
      false
    end
  end

end

Class Method Details

.find_for_autocomplete(params) ⇒ Scope of matching sources

TODO: deprecate

Returns:

  • (Scope of matching sources)


70
71
72
73
74
75
# File 'app/models/citation.rb', line 70

def self.find_for_autocomplete(params)
  term = params['term']
  ending = term + '%'
  wrapped = '%' + term + '%'
  joins(:source).where('sources.cached ILIKE ? OR sources.cached ILIKE ? OR citation_object_type LIKE ?', ending, wrapped, ending).with_project_id(params[:project_id])
end

Instance Method Details

#add_source_to_projectObject (protected)



103
104
105
106
107
108
# File 'app/models/citation.rb', line 103

def add_source_to_project
  if !ProjectSource.where(source: source).any?
    ProjectSource.create(project: project, source: source)
  end
  true
end

#first_pageString?

Returns the first integer in the string, as a string

Returns:

  • (String, nil)

    the first integer in the string, as a string



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

def first_page
  /(?<i>\d+)/ =~ pages
  i 
end

#is_original?Boolean

Returns true if is_original is checked, false if nil/false

Returns:

  • (Boolean)

    true if is_original is checked, false if nil/false



79
80
81
# File 'app/models/citation.rb', line 79

def is_original?
  is_original ? true : false
end

#prevent_if_requiredObject (protected)

TODO: modify for asserted distributions and other origin style relationships



126
127
128
129
130
131
# File 'app/models/citation.rb', line 126

def prevent_if_required
  if !marked_for_destruction? && !new_record? && citation_object.requires_citation? && citation_object.citations.reload.count == 1
    errors.add(:base, 'at least one citation is required')
    throw :abort
  end
end

#reject_citation_topics(attributed) ⇒ Object (protected)



110
111
112
# File 'app/models/citation.rb', line 110

def reject_citation_topics(attributed)
  attributes['id'].blank? && attributed['topic_id'].blank? && attributed['topic'].blank? && attributed['topic_attributes'].blank?
end

#reject_topic(attributed) ⇒ Object (protected)



114
115
116
# File 'app/models/citation.rb', line 114

def reject_topic(attributed)
  attributed['name'].blank? || attributed['definition'].blank?
end

#set_cached_names_for_taxon_namesObject (protected)



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
# File 'app/models/citation.rb', line 133

def set_cached_names_for_taxon_names
  if citation_object_type == 'TaxonNameRelationship' && TAXON_NAME_RELATIONSHIP_NAMES_INVALID.include?(citation_object.try(:type_name))
    begin
      TaxonNameRelationship.transaction do
        t = citation_object.subject_taxon_name
        vn = t.get_valid_taxon_name

        t.update_columns(
            cached: t.get_full_name,
            cached_html: t.get_full_name_html,
            cached_valid_taxon_name_id: vn.id)
        t.combination_list_self.each do |c|
          c.update_column(:cached_valid_taxon_name_id, vn.id)
        end

        vn.list_of_invalid_taxon_names.each do |s|
          s.update_column(:cached_valid_taxon_name_id, vn.id)
          s.combination_list_self.each do |c|
            c.update_column(:cached_valid_taxon_name_id, vn.id)
          end
        end
      end
    rescue ActiveRecord::RecordInvalid
      raise
    end
    false
  end
end

#target_documentDocument?

Returns:



97
98
99
# File 'app/models/citation.rb', line 97

def target_document
  documents.order('documentation.position').first
end

#target_document_pageInteger?

Returns if a target document

Returns:

  • (Integer, nil)

    if a target document



92
93
94
# File 'app/models/citation.rb', line 92

def target_document_page
  target_document.try(:pdf_page_for, first_page).try(:first)
end


118
119
120
121
122
123
# File 'app/models/citation.rb', line 118

def update_related_cached_values
  if citation_object_type == 'TaxonName'
    citation_object.update_attribute(:cached_author_year, citation_object.get_author_and_year)
  end
  true
end