Module: ActiveVersion::Revisions::HasRevisions::ClassMethods

Defined in:
lib/active_version/revisions/has_revisions.rb

Instance Method Summary collapse

Instance Method Details

#apply_revision_table_name!(klass) ⇒ Object



148
149
150
151
152
153
154
155
# File 'lib/active_version/revisions/has_revisions.rb', line 148

def apply_revision_table_name!(klass)
  options = ActiveVersion.registry.config_for(self, :revisions) || {}
  custom_table_name = options[:table_name]
  return klass unless custom_table_name && klass.respond_to?(:table_name=)

  klass.table_name = custom_table_name.to_s
  klass
end

#class_revision_enabled?Boolean

Returns:

  • (Boolean)


222
223
224
# File 'lib/active_version/revisions/has_revisions.rb', line 222

def class_revision_enabled?
  @class_revision_enabled != false
end

#create_snapshots(opts = {}) ⇒ Object

Create snapshots for all records



187
188
189
190
191
192
193
# File 'lib/active_version/revisions/has_revisions.rb', line 187

def create_snapshots(opts = {})
  scope = opts[:only_missing] ? where.missing(:revisions) : all

  scope.find_each do |record|
    record.create_snapshot!(opts)
  end
end

#has_revisions(options = {}) ⇒ Object

Declare that a model has revisions



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
# File 'lib/active_version/revisions/has_revisions.rb', line 93

def has_revisions(options = {})
  # Store custom revision class if specified
  if options[:as]
    @custom_revision_class = options[:as]
    options = options.except(:as)
  end

  # Normalize and store options
  self.revision_options = normalize_revision_options(options)

  # Register options before resolving revision FK so custom foreign_key
  # is visible while associations are being built.
  ActiveVersion.registry.register(self, :revisions, revision_options)

  # Ensure association is set up after custom class option is known.
  @revision_associations_setup = false
  setup_revision_associations if respond_to?(:setup_revision_associations)

  # Initialize enabled state (default to true)
  @class_revision_enabled = true

  # Set up callbacks based on options
  setup_revision_callbacks(revision_options)

  # Register with version registry (idempotent)
  ActiveVersion.registry.register(self, :revisions, revision_options)
end

#has_revisions?Boolean

Check if model has revisions configured

Returns:

  • (Boolean)


122
123
124
# File 'lib/active_version/revisions/has_revisions.rb', line 122

def has_revisions?
  revision_options.present?
end

#normalize_identity_columns(value) ⇒ Object



141
142
143
144
145
146
# File 'lib/active_version/revisions/has_revisions.rb', line 141

def normalize_identity_columns(value)
  return nil if value.nil?
  return value.map(&:to_s) if value.is_a?(Array)

  value.to_s
end

#normalize_revision_options(options) ⇒ Object

Normalize revision options



127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/active_version/revisions/has_revisions.rb', line 127

def normalize_revision_options(options)
  {
    on: Array.wrap(options[:on] || [:update]),
    if: options[:if],
    unless: options[:unless],
    auto: options.fetch(:auto, true),
    only: Array.wrap(options[:only] || []).map(&:to_s),
    except: Array.wrap(options[:except] || []).map(&:to_s),
    foreign_key: normalize_identity_columns(options[:foreign_key]),
    identity_resolver: options[:identity_resolver],
    table_name: options[:table_name]
  }
end

#register_revision_column_mappings_from_destination(revision_klass) ⇒ Object



157
158
159
160
161
162
# File 'lib/active_version/revisions/has_revisions.rb', line 157

def register_revision_column_mappings_from_destination(revision_klass)
  return unless revision_klass.respond_to?(:revision_column_for)
  version_column = revision_klass.revision_column_for(:version)
  return unless version_column
  ActiveVersion.column_mapper.register(self, :revisions, :version, version_column)
end

#revision_on_updateObject

Manual callback installation methods



182
183
184
# File 'lib/active_version/revisions/has_revisions.rb', line 182

def revision_on_update
  before_update :create_revision_before_update, if: :should_create_revision?
end

#setup_revision_callbacks(options) ⇒ Object

Set up callbacks based on options



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/active_version/revisions/has_revisions.rb', line 165

def setup_revision_callbacks(options)
  # Remove existing callbacks first if they exist
  if respond_to?(:_update_callbacks)
    callbacks = _update_callbacks.select { |cb| cb.filter == :create_revision_before_update }
    callbacks.each { |cb| skip_callback(:update, :before, :create_revision_before_update) }
  end

  # If auto is false or on is empty, don't install callbacks automatically
  return if options[:auto] == false || options[:on] == []

  # Install callbacks for specified events
  if options[:on].include?(:update)
    before_update :create_revision_before_update, if: :should_create_revision?
  end
end

#with_revisionsObject

Enable revisions for a block



214
215
216
217
218
219
220
# File 'lib/active_version/revisions/has_revisions.rb', line 214

def with_revisions
  revision_was_enabled = class_revision_enabled?
  enable_revisions
  yield
ensure
  disable_revisions unless revision_was_enabled
end

#without_revisionsObject

Disable revisions for a block



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/active_version/revisions/has_revisions.rb', line 196

def without_revisions
  callbacks = if respond_to?(:_update_callbacks)
    _update_callbacks.select { |cb| cb.filter == :create_revision_before_update }
  else
    []
  end
  callback_installed = callbacks.any?

  skip_callback(:update, :before, :create_revision_before_update) if callback_installed
  yield
ensure
  # Restore callback if it was set up
  if callback_installed && revision_options && revision_options[:auto] != false && revision_options[:on].include?(:update)
    set_callback(:update, :before, :create_revision_before_update, if: :should_create_revision?)
  end
end