SMERM/EMUForm

View on GitHub
app/models/work.rb

Summary

Maintainability
A
0 mins
Test Coverage
#
# +Work+:
#
# represent a single work
#
class Work < ActiveRecord::Base

  belongs_to :owner, class_name: 'Account'
  belongs_to :edition
  belongs_to :category

  validates_presence_of :title, :year, :duration, :instruments, :program_notes_en, :owner_id, :edition_id, :category_id

  has_many :submitted_files
  has_many :works_roles_authors
  has_many :authors, through: :works_roles_authors, dependent: :destroy

  accepts_nested_attributes_for :submitted_files, :allow_destroy => true, :reject_if => proc { |attrs| attrs[:http_channel].blank? }
  accepts_nested_attributes_for :authors

  UPLOAD_COND_PATH = Rails.env == 'test' ? 'spec' : 'public'
  UPLOAD_BASE_PATH = File.join(Rails.root, UPLOAD_COND_PATH, 'private', 'uploads')
  UPLOAD_PREFIX = "EF#{Time.zone.now.year}_"
  UPLOAD_SUFFIX = ''

  #
  # +authors_attributes=(attrs)+ + +after_save+
  #
  # overrides the default in order to take care of the three-way many-to-many
  # relationship between work, roles and authors.
  #
  # This prepares the records which are saved at a later time through the
  # +after_save+ callback +:create_authors_roles_links+
  #
  # It clears the all the previous attributions (if any) so that the work
  # record may be updated.
  #
  after_save :create_authors_roles_links

  def authors_attributes=(attrs)
    @_wras_ = []
    attrs.each do
      |h|
      h[:roles_attributes].each do
        |rh|
        # add only if rh[:id] is actually present (view adds an empty one at the end)
        @_wras_ << WorkRoleAuthor.new(author_id: h[:id], role_id: rh[:id]) unless rh[:id].blank?
      end
    end
    @_wras_
  end

  #
  # +submitted_files_attributes=(attrs)+ + +after_save+
  #
  # This prepares the records which are saved at a later time through the
  # +after_save+ callback +:create_submitted_files_links+
  #
  after_save :create_submitted_files_links

  def submitted_files_attributes=(attrs)
    @_sfs_ = attrs
  end

  #
  # +before_validation+
  #
  # set the edition appropriately for this work
  #
  before_validation :add_edition

  #
  # +after_validation+
  #
  # The +create_directory+ is called after validation is passed to generate
  # the proper landing directory for all submitted files.
  # If +Work+ is created without an <tt>args['directory']</tt> parameter, it
  # creates a directory using the +Dir::Tmpname.make_tmpname+ method
  #
  after_validation :create_directory

  #
  # +before_destroy+ clears the directory containing the media
  #
  before_destroy :clear_directory

  #
  # displaying these attribute requires some conditioning
  #
  # +display_duration+ should be in the form hh:mm:ss
  #
  def display_duration
    res = self.duration
    res.kind_of?(Time) ?  res.strftime("%H:%M:%S") : ''
  end

  #
  # +display_year+ should be in the form yyyy
  #
  def display_year
    res = self.year
    res.kind_of?(Time) ? res.year : ''
  end

  #
  # +year=+ when actually writing a composition year, since inserting a single
  # year has an hysteresis connect to local time zones we should add a couple
  # of days to it to make sure we get the proper year set
  #
  def year=(val)
    write_attribute(:year, year_anti_hystheresis(val))
  end

  #
  # +clear_directory+ will remove the directory referenced by the object,
  # if present, and clear the field. It returns the removed directory
  #
  def clear_directory
    res = nil
    unless self.directory.blank?
      res = self.directory
      FileUtils.rm_rf(self.directory, :secure => true)
      self.directory = nil
    end
    res
  end

  #
  # <tt>display_authors_with_roles(force = false)</tt>
  #
  # creates a string with authors and roles in the form:
  #
  # `Evelyn Fernandez (Music Composer, Text Author), Sheila Shanti (Video Director), ...`
  #
  def display_authors_with_roles(force = false)
    self.authors(force).uniq.map { |a| '%s (%s)' % [ a.full_name, a.roles(force).for_work(self.to_param).uniq.map { |r| r.description }.join(', ') ] }.join(', ')
  end

private

  def create_directory
    self.directory = Dir::Tmpname.make_tmpname(File.join(UPLOAD_BASE_PATH, UPLOAD_PREFIX), UPLOAD_SUFFIX) unless self.directory
    FileUtils.mkdir_p(self.directory)
  end

  def year_anti_hystheresis(val)
    res = val.kind_of?(Time) ? val : Time.zone.parse(val.to_s)
    res + 2.days
  end

  def create_authors_roles_links
    unless @_wras_.blank?
      @_wras_.each do
        |wra|
        wra.update(work_id: self.to_param)
        wra.save
      end
    end
  end

  def create_submitted_files_links
    @_sfs_.each { |sf_args| SubmittedFile.upload(sf_args[:http_request], self) } unless @_sfs_.blank?
  end

  #
  # +add_edition+
  #
  # adds the current edition to the work as a reference unless it is already set.
  # Aptly called from a # +before_validation+ callback.
  #
  def add_edition
    self.edition = Edition.current unless self.edition
  end

end