Module: FatJam::ActsAsRevisable::Common

Defined in:
lib/acts_as_revisable/acts/common.rb

Overview

This module is mixed into the revision and revisable classes.

Callbacks

  • before_branch is called on the Revisable or Revision that is being branched

  • after_branch is called on the Revisable or Revision that is being branched

Defined Under Namespace

Modules: ClassMethods

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object

:nodoc:



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/acts_as_revisable/acts/common.rb', line 12

def self.included(base) #:nodoc:
  base.send(:extend, ClassMethods)
  
  base.class_inheritable_hash :revisable_after_callback_blocks
  base.revisable_after_callback_blocks = {}
  
  base.class_inheritable_hash :revisable_current_states
  base.revisable_current_states = {}
  
  class << base
    alias_method_chain :instantiate, :revisable
  end

  base.instance_eval do
    define_callbacks :before_branch, :after_branch      
    has_many :branches, (revisable_options.revision_association_options || {}).merge({:class_name => base.class_name, :foreign_key => :revisable_branched_from_id})
              
    belongs_to :branch_source, :class_name => base.class_name, :foreign_key => :revisable_branched_from_id
    after_save :execute_blocks_after_save
    disable_revisable_scope :branch_source, :branches
  end        
end

Instance Method Details

#branch(*args, &block) ⇒ Object

Branch the Revisable or Revision and return the new revisable instance. The instance has not been saved yet.

Callbacks

  • before_branch is called on the Revisable or Revision that is being branched

  • after_branch is called on the Revisable or Revision that is being branched

  • after_branch_created is called on the newly created Revisable instance.



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
# File 'lib/acts_as_revisable/acts/common.rb', line 63

def branch(*args, &block)
  is_branching!
  
  unless run_callbacks(:before_branch) { |r, o| r == false}
    raise ActiveRecord::RecordNotSaved
  end

  options = args.extract_options!
  options[:revisable_branched_from_id] = self.id
  self.class.column_names.each do |col|
    next unless self.class.revisable_should_clone_column? col
    options[col.to_sym] = self[col] unless options.has_key?(col.to_sym)
  end
  
  br = self.class.revisable_class.new(options)
  br.is_branching!
  
  br.execute_after(:save) do
    begin
      run_callbacks(:after_branch)
      br.run_callbacks(:after_branch_created)
    ensure
      br.is_branching!(false)
      is_branching!(false)
    end
  end
  
  block.call(br) if block_given?
  
  br
end

#branch!(*args) ⇒ Object

Same as #branch except it calls #save! on the new Revisable instance.



96
97
98
99
100
# File 'lib/acts_as_revisable/acts/common.rb', line 96

def branch!(*args)
  branch(*args) do |br|
    br.save!
  end
end

#current_revision?Boolean

Returns true if the instance is the current record and not a revision.

Returns:

  • (Boolean)


148
149
150
# File 'lib/acts_as_revisable/acts/common.rb', line 148

def current_revision?
  self.is_a? self.class.revisable_class
end

#diffs(what) ⇒ Object



157
158
159
160
161
162
163
164
# File 'lib/acts_as_revisable/acts/common.rb', line 157

def diffs(what)
  what = current_revision.find_revision(what)
  returning({}) do |changes|
    self.class.revisable_class.revisable_watch_columns.each do |c|
      changes[c] = [self[c], what[c]] unless self[c] == what[c]
    end
  end
end

#execute_after(key, &block) ⇒ Object

Stores a block for later execution after a given callback. The parameter key is the callback the block should be executed after.



47
48
49
50
51
# File 'lib/acts_as_revisable/acts/common.rb', line 47

def execute_after(key, &block) #:nodoc:
  return unless block_given?
  revisable_after_callback_blocks[key] ||= []
  revisable_after_callback_blocks[key] << block
end

#execute_blocks_after_saveObject

Executes the blocks stored in an accessor after a save.



36
37
38
39
40
41
42
# File 'lib/acts_as_revisable/acts/common.rb', line 36

def execute_blocks_after_save #:nodoc:
  return unless revisable_after_callback_blocks[:save]
  revisable_after_callback_blocks[:save].each do |block|
    block.call
  end
  revisable_after_callback_blocks.delete(:save)
end

#first_revision?Boolean

Returns true if the instance is the first revision.

Returns:

  • (Boolean)


138
139
140
# File 'lib/acts_as_revisable/acts/common.rb', line 138

def first_revision?
  self.revision_number == 1
end

#get_revisable_state(type) ⇒ Object

Returns the state of the given record.



131
132
133
134
135
# File 'lib/acts_as_revisable/acts/common.rb', line 131

def get_revisable_state(type) #:nodoc:
  key = self.read_attribute(self.class.primary_key)
  revisable_current_states[type] ||= {}
  revisable_current_states[type][key] || revisable_current_states[type][object_id] || false
end

#is_branching!(value = true) ⇒ Object

Globally sets the reverting state of this record.



103
104
105
# File 'lib/acts_as_revisable/acts/common.rb', line 103

def is_branching!(value=true) #:nodoc:
  set_revisable_state(:branching, value)
end

#is_branching?Boolean

Returns true if the record (not just this instance of the record) is currently being branched.

Returns:

  • (Boolean)


109
110
111
# File 'lib/acts_as_revisable/acts/common.rb', line 109

def is_branching?
  get_revisable_state(:branching)
end

#latest_revision?Boolean

Returns true if the instance is the most recent revision.

Returns:

  • (Boolean)


143
144
145
# File 'lib/acts_as_revisable/acts/common.rb', line 143

def latest_revision?
  self.revision_number == self.current_revision.revision_number
end

#original_idObject

When called on a Revision it returns the original id. When called on a Revisable it returns the id.



115
116
117
# File 'lib/acts_as_revisable/acts/common.rb', line 115

def original_id
  self[:revisable_original_id] || self[:id]
end

#revision_numberObject

Accessor for revisable_number just to make external API more pleasant.



153
154
155
# File 'lib/acts_as_revisable/acts/common.rb', line 153

def revision_number
  self[:revisable_number]
end

#set_revisable_state(type, value) ⇒ Object

Globally sets the state for a given record. This is keyed on the primary_key of a saved record or the object_id on a new instance.



122
123
124
125
126
127
128
# File 'lib/acts_as_revisable/acts/common.rb', line 122

def set_revisable_state(type, value) #:nodoc:
  key = self.read_attribute(self.class.primary_key)
  key = object_id if key.nil?
  revisable_current_states[type] ||= {}
  revisable_current_states[type][key] = value
  revisable_current_states[type].delete(key) unless value
end