journal.rb 3.53 KB
Newer Older
1
#-- encoding: UTF-8
2 3
#-- copyright
# ChiliProject is a project management system.
4
#
Holger Just's avatar
Holger Just committed
5
# Copyright (C) 2010-2013 the ChiliProject Team
6
#
7 8 9 10
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
11
#
12 13 14
# See doc/COPYRIGHT.rdoc for more details.
#++

15 16 17 18 19 20 21 22 23 24 25 26
require_dependency 'journal_formatter'

# The ActiveRecord model representing journals.
class Journal < ActiveRecord::Base
  unloadable

  include Comparable
  include JournalFormatter
  include JournalDeprecated

  # Make sure each journaled model instance only has unique version ids
  validates_uniqueness_of :version, :scope => [:journaled_id, :type]
27 28 29 30 31

  # Define a default class_name to prevent `uninitialized constant Journal::Journaled`
  # subclasses will be given an actual class name when they are created by aaj
  #
  #  e.g. IssueJournal will get :class_name => 'Issue'
32
  belongs_to :journaled, :class_name => 'Journal'
33 34
  belongs_to :user

35 36 37
  # "touch" the journaled object on creation
  after_create :touch_journaled_after_creation

38 39 40 41 42 43 44
  # ActiveRecord::Base#changes is an existing method, so before serializing the +changes+ column,
  # the existing +changes+ method is undefined. The overridden +changes+ method pertained to
  # dirty attributes, but will not affect the partial updates functionality as that's based on
  # an underlying +changed_attributes+ method, not +changes+ itself.
  # undef_method :changes
  serialize :changes, Hash

45 46 47 48
  def touch_journaled_after_creation
    journaled.touch
  end

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
  # In conjunction with the included Comparable module, allows comparison of journal records
  # based on their corresponding version numbers, creation timestamps and IDs.
  def <=>(other)
    [version, created_at, id].map(&:to_i) <=> [other.version, other.created_at, other.id].map(&:to_i)
  end

  # Returns whether the version has a version number of 1. Useful when deciding whether to ignore
  # the version during reversion, as initial versions have no serialized changes attached. Helps
  # maintain backwards compatibility.
  def initial?
    version < 2
  end

  # The anchor number for html output
  def anchor
    version - 1
  end

  # Possible shortcut to the associated project
  def project
    if journaled.respond_to?(:project)
      journaled.project
    elsif journaled.is_a? Project
      journaled
    else
      nil
    end
  end

  def editable_by?(user)
    journaled.journal_editable_by?(user)
  end

  def details
    attributes["changes"] || {}
  end

  alias_method :changes, :details

  def new_value_for(prop)
    details[prop.to_s].last if details.keys.include? prop.to_s
  end

  def old_value_for(prop)
    details[prop.to_s].first if details.keys.include? prop.to_s
  end
95

96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
  # Returns a string of css classes
  def css_classes
    s = 'journal'
    s << ' has-notes' unless notes.blank?
    s << ' has-details' unless details.empty?
    s
  end

  # This is here to allow people to disregard the difference between working with a
  # Journal and the object it is attached to.
  # The lookup is as follows:
  ## => Call super if the method corresponds to one of our attributes (will end up in AR::Base)
  ## => Try the journaled object with the same method and arguments
  ## => On error, call super
  def method_missing(method, *args, &block)
111
    return super if respond_to?(method) || attributes[method.to_s]
112 113 114 115 116 117
    journaled.send(method, *args, &block)
  rescue NoMethodError => e
    e.name == method ? super : raise(e)
  end

end