Class: Sound

Overview

A Sound is a digital representation of some noise. They are linked via Conveyances as Images are linked via Depictions.

Defined Under Namespace

Modules: DwcMediaExtensions

Constant Summary collapse

ALLOWED_CONTENT_TYPES =

See canonical list at

%w{
  audio/wma
  audio/flac
  audio/mp3
  audio/ogg
  audio/wav
  audio/x-wav
  audio/x-ms-wma
  audio/m4a
  audio/mpeg
}

Constants included from DwcMediaExtensions

DwcMediaExtensions::DWC_MEDIA_SOUND_EXTENSION_MAP

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Shared::IsData

#errors_excepting, #full_error_messages_excepting, #identical, #is_community?, #is_destroyable?, #is_editable?, #is_in_use?, #is_in_users_projects?, #metamorphosize, #similar

Methods included from DwcMediaExtensions

#darwin_core_media_extension_sound_row, #dwc_media_access_uri, #dwc_media_dc_format, #dwc_media_dc_type, #dwc_media_dcmi_type

Methods included from Shared::Tags

#reject_tags, #tag_with, #tagged?, #tagged_with?

Methods included from Shared::Notes

#concatenated_notes_string, #reject_notes

Methods included from Shared::Identifiers

#dwc_occurrence_id, #identified?, #next_by_identifier, #previous_by_identifier, #reject_identifiers, #uri, #uuid

Methods included from Shared::DataAttributes

#import_attributes, #internal_attributes, #keyword_value_hash, #reject_data_attributes

Methods included from Shared::Attributions

#attributed?, #reject_attribution

Methods included from Shared::Citations

#cited?, #mark_citations_for_destruction, #nomenclature_date, #origin_citation_source_id, #reject_citations, #requires_citation?, #sources_by_topic_id

Methods included from Shared::ProtocolRelationships

#machine_output?, #protocolled?, #reject_protocols

Methods included from Shared::Confidences

#reject_confidences

Methods included from Shared::OriginRelationship

#new_objects, #old_objects, #reject_origin_relationships, #set_origin

Methods included from Shared::MatrixHooks::Member

#member_add_matrix_columns, #member_add_matrix_rows, #member_add_to_matrix_items, #member_of_new_matrix_column_items, #member_of_new_matrix_row_items, #member_of_old_matrix_column_items, #member_of_old_matrix_row_items, #member_remove_from_matrix_items, #member_remove_matrix_columns, #member_remove_matrix_rows, #member_synchronize_matrices, #member_update_matrix_items?

Methods included from Housekeeping

#has_polymorphic_relationship?

Methods inherited from ApplicationRecord

transaction_with_retry

Instance Attribute Details

#nameString

A label for the sound.

Returns:

  • (String)


14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
# File 'app/models/sound.rb', line 14

class Sound < ApplicationRecord
  include Housekeeping
  include Shared::MatrixHooks::Member
  include Shared::OriginRelationship
  include Shared::Observations
  include Shared::Confidences
  include Shared::ProtocolRelationships
  include Shared::Citations
  include Shared::Attributions
  include Shared::DataAttributes
  include Shared::Identifiers
  include Shared::Notes
  include Shared::Tags
  include Sound::DwcMediaExtensions
  include Shared::IsData

  # See canonical list at
  ALLOWED_CONTENT_TYPES = %w{
    audio/wma
    audio/flac
    audio/mp3
    audio/ogg
    audio/wav
    audio/x-wav
    audio/x-ms-wma
    audio/m4a
    audio/mpeg
  }

  originates_from 'Specimen', 'Lot', 'RangedLot', 'Otu', 'CollectionObject', 'FieldOccurrence', 'CollectingEvent'

  has_one_attached :sound_file
  has_many :conveyances, inverse_of: :sound, dependent: :restrict_with_error

  has_many :otus, through: :conveyances, source: :conveyance_object, source_type: 'Otu'

  after_destroy :purge_sound_file

  validate :file_type

  accepts_nested_attributes_for :conveyances, allow_destroy: false

  scope :with_taxon_names, -> {
    joins(:otus)
    .joins("JOIN taxon_names ON taxon_names.id = otus.taxon_name_id")
  }

  private

  def file_type
    if !ALLOWED_CONTENT_TYPES.include?(sound_file.content_type)
      errors.add(:sound_file, "#{sound_file.content_type} is not allowed")
    end
  end

  def purge_sound_file
    sound_file.attachment.purge
  end

  def self.used_recently(user_id, project_id, used_on = '')
    i = arel_table
    d = Conveyance.arel_table

    # i is a select manager
    j = d.project(d['sound_id'], d['updated_at'], d['conveyance_object_type']).from(d)
      .where(d['updated_at'].gt( 1.week.ago ))
      .where(d['updated_by_id'].eq(user_id))
      .where(d['project_id'].eq(project_id))
      .order(d['updated_at'].desc)

    z = j.as('recent_i')

    k = Arel::Nodes::InnerJoin.new(z, Arel::Nodes::On.new(
      z['sound_id'].eq(i['id']).and(z['conveyance_object_type'].eq(used_on))
    ))

    joins(k).distinct.pluck(:id)
  end

  # @params target [String] required, one of nil, `CollectionObject`, FieldOccurrence`, `Otu'
  # @return [Hash] sounds optimized for user selection
  def self.select_optimized(user_id, project_id, target = nil)
    r = used_recently(user_id, project_id, target)
    h = {
      quick: [],
      pinboard: Sound.pinned_by(user_id).where(project_id:).to_a,
      recent: []
    }

    if target && !r.empty?
      h[:recent] = (
        Sound.where('"sounds"."id" IN (?)', r.first(5) ).to_a +
        Sound.where(project_id:, created_by_id: user_id, created_at: 3.hours.ago..Time.now)
        .order('updated_at DESC')
        .limit(3).to_a
      ).uniq.sort{|a,b| a.updated_at <=> b.updated_at}

      h[:quick] = (
        Sound.pinned_by(user_id).pinboard_inserted.where(project_id:).to_a +
        Sound.where('"sounds"."id" IN (?)', r.first(4) ).to_a)
        .uniq.sort{|a,b| a.updated_at <=> b.updated_at}
    else
      h[:recent] = Sound.where(project_id:).order('updated_at DESC').limit(10).to_a
      h[:quick] = Sound.pinned_by(user_id).pinboard_inserted.where(pinboard_items: {project_id:}).order('updated_at DESC')
    end

    h
  end

end

#project_idInteger

the project ID

Returns:

  • (Integer)


14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
# File 'app/models/sound.rb', line 14

class Sound < ApplicationRecord
  include Housekeeping
  include Shared::MatrixHooks::Member
  include Shared::OriginRelationship
  include Shared::Observations
  include Shared::Confidences
  include Shared::ProtocolRelationships
  include Shared::Citations
  include Shared::Attributions
  include Shared::DataAttributes
  include Shared::Identifiers
  include Shared::Notes
  include Shared::Tags
  include Sound::DwcMediaExtensions
  include Shared::IsData

  # See canonical list at
  ALLOWED_CONTENT_TYPES = %w{
    audio/wma
    audio/flac
    audio/mp3
    audio/ogg
    audio/wav
    audio/x-wav
    audio/x-ms-wma
    audio/m4a
    audio/mpeg
  }

  originates_from 'Specimen', 'Lot', 'RangedLot', 'Otu', 'CollectionObject', 'FieldOccurrence', 'CollectingEvent'

  has_one_attached :sound_file
  has_many :conveyances, inverse_of: :sound, dependent: :restrict_with_error

  has_many :otus, through: :conveyances, source: :conveyance_object, source_type: 'Otu'

  after_destroy :purge_sound_file

  validate :file_type

  accepts_nested_attributes_for :conveyances, allow_destroy: false

  scope :with_taxon_names, -> {
    joins(:otus)
    .joins("JOIN taxon_names ON taxon_names.id = otus.taxon_name_id")
  }

  private

  def file_type
    if !ALLOWED_CONTENT_TYPES.include?(sound_file.content_type)
      errors.add(:sound_file, "#{sound_file.content_type} is not allowed")
    end
  end

  def purge_sound_file
    sound_file.attachment.purge
  end

  def self.used_recently(user_id, project_id, used_on = '')
    i = arel_table
    d = Conveyance.arel_table

    # i is a select manager
    j = d.project(d['sound_id'], d['updated_at'], d['conveyance_object_type']).from(d)
      .where(d['updated_at'].gt( 1.week.ago ))
      .where(d['updated_by_id'].eq(user_id))
      .where(d['project_id'].eq(project_id))
      .order(d['updated_at'].desc)

    z = j.as('recent_i')

    k = Arel::Nodes::InnerJoin.new(z, Arel::Nodes::On.new(
      z['sound_id'].eq(i['id']).and(z['conveyance_object_type'].eq(used_on))
    ))

    joins(k).distinct.pluck(:id)
  end

  # @params target [String] required, one of nil, `CollectionObject`, FieldOccurrence`, `Otu'
  # @return [Hash] sounds optimized for user selection
  def self.select_optimized(user_id, project_id, target = nil)
    r = used_recently(user_id, project_id, target)
    h = {
      quick: [],
      pinboard: Sound.pinned_by(user_id).where(project_id:).to_a,
      recent: []
    }

    if target && !r.empty?
      h[:recent] = (
        Sound.where('"sounds"."id" IN (?)', r.first(5) ).to_a +
        Sound.where(project_id:, created_by_id: user_id, created_at: 3.hours.ago..Time.now)
        .order('updated_at DESC')
        .limit(3).to_a
      ).uniq.sort{|a,b| a.updated_at <=> b.updated_at}

      h[:quick] = (
        Sound.pinned_by(user_id).pinboard_inserted.where(project_id:).to_a +
        Sound.where('"sounds"."id" IN (?)', r.first(4) ).to_a)
        .uniq.sort{|a,b| a.updated_at <=> b.updated_at}
    else
      h[:recent] = Sound.where(project_id:).order('updated_at DESC').limit(10).to_a
      h[:quick] = Sound.pinned_by(user_id).pinboard_inserted.where(pinboard_items: {project_id:}).order('updated_at DESC')
    end

    h
  end

end

Class Method Details

.select_optimized(user_id, project_id, target = nil) ⇒ Hash (private)

Returns sounds optimized for user selection.

Returns:

  • (Hash)

    sounds optimized for user selection



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

def self.select_optimized(user_id, project_id, target = nil)
  r = used_recently(user_id, project_id, target)
  h = {
    quick: [],
    pinboard: Sound.pinned_by(user_id).where(project_id:).to_a,
    recent: []
  }

  if target && !r.empty?
    h[:recent] = (
      Sound.where('"sounds"."id" IN (?)', r.first(5) ).to_a +
      Sound.where(project_id:, created_by_id: user_id, created_at: 3.hours.ago..Time.now)
      .order('updated_at DESC')
      .limit(3).to_a
    ).uniq.sort{|a,b| a.updated_at <=> b.updated_at}

    h[:quick] = (
      Sound.pinned_by(user_id).pinboard_inserted.where(project_id:).to_a +
      Sound.where('"sounds"."id" IN (?)', r.first(4) ).to_a)
      .uniq.sort{|a,b| a.updated_at <=> b.updated_at}
  else
    h[:recent] = Sound.where(project_id:).order('updated_at DESC').limit(10).to_a
    h[:quick] = Sound.pinned_by(user_id).pinboard_inserted.where(pinboard_items: {project_id:}).order('updated_at DESC')
  end

  h
end

.used_recently(user_id, project_id, used_on = '') ⇒ Object (private)



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'app/models/sound.rb', line 73

def self.used_recently(user_id, project_id, used_on = '')
  i = arel_table
  d = Conveyance.arel_table

  # i is a select manager
  j = d.project(d['sound_id'], d['updated_at'], d['conveyance_object_type']).from(d)
    .where(d['updated_at'].gt( 1.week.ago ))
    .where(d['updated_by_id'].eq(user_id))
    .where(d['project_id'].eq(project_id))
    .order(d['updated_at'].desc)

  z = j.as('recent_i')

  k = Arel::Nodes::InnerJoin.new(z, Arel::Nodes::On.new(
    z['sound_id'].eq(i['id']).and(z['conveyance_object_type'].eq(used_on))
  ))

  joins(k).distinct.pluck(:id)
end

Instance Method Details

#file_typeObject (private)



63
64
65
66
67
# File 'app/models/sound.rb', line 63

def file_type
  if !ALLOWED_CONTENT_TYPES.include?(sound_file.content_type)
    errors.add(:sound_file, "#{sound_file.content_type} is not allowed")
  end
end

#purge_sound_fileObject (private)



69
70
71
# File 'app/models/sound.rb', line 69

def purge_sound_file
  sound_file.attachment.purge
end