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?

Methods included from ActiverecordUtilities

#trim_attributes

Instance Attribute Details

- (Integer) citation_object_id

Returns Rails STI, the id of the object being cited

Returns:

  • (Integer)

    Rails STI, the id of the object being cited



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

class Citation < ApplicationRecord

  # Citations do not have Confidence or DataAttribute.

  include Housekeeping
  include Shared::Notes
  include Shared::Tags
  include Shared::IsData
  include Shared::PolymorphicAnnotator
  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

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

  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?

  # 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

  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

end

- (String) citation_object_type

Returns Rails STI, the class of the object being cited

Returns:

  • (String)

    Rails STI, the class of the object being cited



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

class Citation < ApplicationRecord

  # Citations do not have Confidence or DataAttribute.

  include Housekeeping
  include Shared::Notes
  include Shared::Tags
  include Shared::IsData
  include Shared::PolymorphicAnnotator
  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

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

  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?

  # 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

  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

end

- (Boolean) is_original

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?



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

class Citation < ApplicationRecord

  # Citations do not have Confidence or DataAttribute.

  include Housekeeping
  include Shared::Notes
  include Shared::Tags
  include Shared::IsData
  include Shared::PolymorphicAnnotator
  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

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

  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?

  # 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

  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

end

- (String?) pages

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



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

class Citation < ApplicationRecord

  # Citations do not have Confidence or DataAttribute.

  include Housekeeping
  include Shared::Notes
  include Shared::Tags
  include Shared::IsData
  include Shared::PolymorphicAnnotator
  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

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

  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?

  # 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

  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

end

- (Integer) project_id

the project ID

Returns:

  • (Integer)


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

class Citation < ApplicationRecord

  # Citations do not have Confidence or DataAttribute.

  include Housekeeping
  include Shared::Notes
  include Shared::Tags
  include Shared::IsData
  include Shared::PolymorphicAnnotator
  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

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

  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?

  # 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

  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

end

- (Integer) source_id

the source ID

Returns:

  • (Integer)


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

class Citation < ApplicationRecord

  # Citations do not have Confidence or DataAttribute.

  include Housekeeping
  include Shared::Notes
  include Shared::Tags
  include Shared::IsData
  include Shared::PolymorphicAnnotator
  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

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

  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?

  # 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

  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

end

Class Method Details

+ (Scope of matching sources) find_for_autocomplete(params)

TODO: deprecate

Returns:

  • (Scope of matching sources)


61
62
63
64
65
66
# File 'app/models/citation.rb', line 61

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

- (Object) add_source_to_project (protected)



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

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

- (String?) first_page

Returns the first integer in the string, as a string

Returns:

  • (String, nil)

    the first integer in the string, as a string



76
77
78
79
# File 'app/models/citation.rb', line 76

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

- (Boolean) is_original?

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

Returns:

  • (Boolean)

    true if is_original is checked, false if nil/false



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

def is_original?
  is_original ? true : false
end

- (Object) prevent_if_required (protected)



116
117
118
119
120
121
# File 'app/models/citation.rb', line 116

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

- (Object) reject_citation_topics(attributed) (protected)



101
102
103
# File 'app/models/citation.rb', line 101

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

- (Object) reject_topic(attributed) (protected)



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

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

- (Document?) target_document

Returns:



88
89
90
# File 'app/models/citation.rb', line 88

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

- (Integer?) target_document_page

Returns if a target document

Returns:

  • (Integer, nil)

    if a target document



83
84
85
# File 'app/models/citation.rb', line 83

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


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

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