Module: Logidze::Model

Extended by:
ActiveSupport::Concern
Defined in:
lib/logidze/model.rb

Overview

Extends model with methods to browse history rubocop: disable Metrics/ModuleLength

Defined Under Namespace

Modules: ClassMethods

Constant Summary collapse

TIME_FACTOR =

Use this to convert Ruby time to milliseconds

1_000

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#logidze_requested_tsObject

Returns the value of attribute logidze_requested_ts.



61
62
63
# File 'lib/logidze/model.rb', line 61

def logidze_requested_ts
  @logidze_requested_ts
end

Instance Method Details

#association(name) ⇒ Object

rubocop: disable Metrics/MethodLength



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/logidze/model.rb', line 172

def association(name)
  association = super

  return association unless Logidze.associations_versioning

  should_apply_logidze =
    logidze_past? &&
    association.klass.respond_to?(:has_logidze?) &&
    !association.singleton_class.include?(Logidze::VersionedAssociation)

  return association unless should_apply_logidze

  association.singleton_class.prepend Logidze::VersionedAssociation

  if association.is_a? ActiveRecord::Associations::CollectionAssociation
    association.singleton_class.prepend(
      Logidze::VersionedAssociation::CollectionAssociation
    )
  end

  association
end

#at(ts = nil, time: nil, version: nil) ⇒ Object

Return a dirty copy of record at specified time If time/version is less then the first version, then return nil. If time/version is greater then the last version, then return self. rubocop: disable Metrics/MethodLength



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/logidze/model.rb', line 67

def at(ts = nil, time: nil, version: nil)
  Deprecations.show_ts_deprecation_for("#at") if ts

  return at_version(version) if version

  time ||= ts
  time = parse_time(time)

  return nil unless log_data.exists_ts?(time)

  if log_data.current_ts?(time)
    self.logidze_requested_ts = time
    return self
  end

  log_entry = log_data.find_by_time(time)

  build_dup(log_entry, time)
end

#at!(ts = nil, time: nil, version: nil) ⇒ Object

Revert record to the version at specified time (without saving to DB)



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/logidze/model.rb', line 89

def at!(ts = nil, time: nil, version: nil)
  Deprecations.show_ts_deprecation_for("#at!") if ts

  return at_version!(version) if version

  time ||= ts
  time = parse_time(time)

  return self if log_data.current_ts?(time)
  return false unless log_data.exists_ts?(time)

  version = log_data.find_by_time(time).version

  apply_diff(version, log_data.changes_to(version: version))
end

#at_version(version) ⇒ Object

Return a dirty copy of specified version of record



106
107
108
109
110
111
112
113
# File 'lib/logidze/model.rb', line 106

def at_version(version)
  return self if log_data.version == version

  log_entry = log_data.find_by_version(version)
  return nil unless log_entry

  build_dup(log_entry)
end

#at_version!(version) ⇒ Object

Revert record to the specified version (without saving to DB)



116
117
118
119
120
121
# File 'lib/logidze/model.rb', line 116

def at_version!(version)
  return self if log_data.version == version
  return false unless log_data.find_by_version(version)

  apply_diff(version, log_data.changes_to(version: version))
end

#diff_from(ts = nil, version: nil, time: nil) ⇒ Object

Return diff object representing changes since specified time.

Examples:


post.diff_from(time: 2.days.ago) # or post.diff_from(version: 2)
#=> { "id" => 1, "changes" => { "title" => { "old" => "Hello!", "new" => "World" } } }


129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/logidze/model.rb', line 129

def diff_from(ts = nil, version: nil, time: nil)
  Deprecations.show_ts_deprecation_for("#diff_from") if ts
  time ||= ts
  time = parse_time(time) if time
  changes = log_data.diff_from(time: time, version: version).tap do |v|
    deserialize_changes!(v)
  end

  changes.delete_if { |k, _v| deleted_column?(k) }

  { "id" => id, "changes" => changes }
end

#redo!Object

Restore record to the future version (if ‘undo!` was applied) Return false if no future version found, otherwise return updated record.



152
153
154
155
156
# File 'lib/logidze/model.rb', line 152

def redo!
  version = log_data.next_version
  return false if version.nil?
  switch_to!(version.version)
end

#switch_to!(version, append: Logidze.append_on_undo) ⇒ Object

Restore record to the specified version. Return false if version is unknown.



160
161
162
163
164
165
166
167
168
169
# File 'lib/logidze/model.rb', line 160

def switch_to!(version, append: Logidze.append_on_undo)
  return false unless at_version(version)

  if append && version < log_version
    update!(log_data.changes_to(version: version))
  else
    at_version!(version)
    self.class.without_logging { save! }
  end
end

#undo!(append: Logidze.append_on_undo) ⇒ Object

Restore record to the previous version. Return false if no previous version found, otherwise return updated record.



144
145
146
147
148
# File 'lib/logidze/model.rb', line 144

def undo!(append: Logidze.append_on_undo)
  version = log_data.previous_version
  return false if version.nil?
  switch_to!(version.version, append: append)
end