SpeciesFileGroup/taxonworks

View on GitHub
app/models/descriptor.rb

Summary

Maintainability
A
3 hrs
Test Coverage
# require_dependency Rails.root.to_s +  '/app/models/observation.rb'
# Descriptors are the general mechanism for describing CollectionObjects (individual specimens) or Otus (taxa).
#
# They come in various types, reflecting the approaches commonly used to describe specimens and OTUs:
#
#  Working - raw notes or images, "primal" observations, not yet refined to states or measurements
#  Qualitative - Represents character/character_state expressions as traditionally understood.
#  Quantitative - Single measurements.
#  Sample - Summaries of multiple observations recorded in a statistical manner. Only valid for Otus. For example "length 42-77mm (n=5, min: 42, max:Only valid for Otus."
#
class Descriptor < ApplicationRecord
  include Housekeeping
  include Shared::Citations
  include Shared::Identifiers
  include Shared::Tags
  include Shared::Notes
  include Shared::Depictions
  include Shared::DataAttributes
  include Shared::AlternateValues
  include Shared::Confidences
  include Shared::Documentation
  include Shared::Depictions
  include Shared::IsData

  include SoftValidation

  acts_as_list scope: [:project_id]

  ALTERNATE_VALUES_FOR = [:name, :short_name, :description_name, :key_name].freeze

  validates_presence_of :name, :type
  validate :type_is_subclassed
  validate :short_name_is_shorter

  # See also /app/models/concerns/shared/observations.rb for additional has_many definitions
  has_many :observations, inverse_of: :descriptor, dependent: :restrict_with_error
  has_many :observation_matrix_column_items, dependent: :destroy, class_name: 'ObservationMatrixColumnItem::Single::Descriptor'
  has_many :observation_matrix_columns, inverse_of: :descriptor

  has_many :observation_matrices, through: :observation_matrix_columns

  soft_validate(:sv_short_name_is_short)

  scope :not_weight_zero, -> {where('NOT "descriptors"."weight" = 0 OR "descriptors"."weight" IS NULL') }

  def self.human_name
    self.name.demodulize.humanize
  end

  # @return String, nil
  #   the corresponding Observation STI class name
  def observation_type
    return nil if type.blank?
    'Observation::' + type.split('::').last
  end

  # @return [String] name of the descriptor in a particular language
  # @params target [Symbol] one of :key, :description, nil
  def target_name(target, language_id)
    n = self.name
    a = nil
    case target
    when :key
      n = self.key_name.nil? ? n : self.key_name
    when :description
      n = self.description_name.nil? ? n : self.description_name
    end
    unless language_id.nil?
      case target
      when :key
        a = AlternateValue::Translation.
          where(alternate_value_object: self, language_id: language_id).
          where("(alternate_values.alternate_value_object_attribute = 'key_name' OR alternate_values.alternate_value_object_attribute = 'name')").
          order(:alternate_value_object_attribute).pluck(:value).first
      when :description
        a = AlternateValue::Translation.
          where(alternate_value_object: self, language_id: language_id).
          where("(alternate_values.alternate_value_object_attribute = 'description_name' OR alternate_values.alternate_value_object_attribute = 'name')").
          order(:alternate_value_object_attribute).pluck(:value).first
      end
    end
    return a.nil? ? n : a
  end

  # TODO: these should be `is_` to follow design pattern
  
  def qualitative?
    type == 'Descriptor::Qualitative'
  end

  def presence_absence?
    type == 'Descriptor::PresenceAbsence'
  end

  def gene?
    type == 'Descriptor::Gene'
  end

  protected

  # TODO: get rid of this
  def type_is_subclassed
    if !DESCRIPTOR_TYPES[type]
      errors.add(:type, 'type must be a valid subclass')
    end
  end

  def short_name_is_shorter
    errors.add(:short_name, 'is longer than name!') if short_name && name && (short_name.length > name.length)
  end

  def sv_short_name_is_short
    soft_validations.add(:short_name, 'should likely be less than 12 characters long') if short_name && short_name.length > 12
  end
end

Dir[Rails.root.to_s + '/app/models/descriptor/**/*.rb'].each { |file| require_dependency file }