Class: PaperTrail::ModelConfig

Inherits:
Object
  • Object
show all
Defined in:
lib/paper_trail/model_config.rb

Overview

Configures an ActiveRecord model, mostly at application boot time, but also sometimes mid-request, with methods like enable/disable.

Constant Summary collapse

E_CANNOT_RECORD_AFTER_DESTROY =
<<-STR.strip_heredoc.freeze
  paper_trail.on_destroy(:after) is incompatible with ActiveRecord's
  belongs_to_required_by_default. Use on_destroy(:before)
  or disable belongs_to_required_by_default.
STR
E_HPT_ABSTRACT_CLASS =
<<~STR.squish.freeze
  An application model (%s) has been configured to use PaperTrail (via
  `has_paper_trail`), but the version model it has been told to use (%s) is
  an `abstract_class`. This could happen when an advanced feature called
  Custom Version Classes (http://bit.ly/2G4ch0G) is misconfigured. When all
  version classes are custom, PaperTrail::Version is configured to be an
  `abstract_class`. This is fine, but all application models must be
  configured to use concrete (not abstract) version models.
STR
E_MODEL_LIMIT_REQUIRES_ITEM_SUBTYPE =
<<~STR.squish.freeze
  To use PaperTrail's per-model limit in your %s model, you must have an
  item_subtype column in your versions table. See documentation sections
  2.e.1 Per-model limit, and 4.b.1 The optional item_subtype column.
STR
DPR_PASSING_ASSOC_NAME_DIRECTLY_TO_VERSIONS_OPTION =
<<~STR.squish
  Passing versions association name as `has_paper_trail versions: %{versions_name}`
  is deprecated. Use `has_paper_trail versions: {name: %{versions_name}}` instead.
  The hash you pass to `versions:` is now passed directly to `has_many`.
STR
DPR_CLASS_NAME_OPTION =
<<~STR.squish
  Passing Version class name as `has_paper_trail class_name: %{class_name}`
  is deprecated. Use `has_paper_trail versions: {class_name: %{class_name}}`
  instead. The hash you pass to `versions:` is now passed directly to `has_many`.
STR

Instance Method Summary collapse

Constructor Details

#initialize(model_class) ⇒ ModelConfig

Returns a new instance of ModelConfig.



37
38
39
# File 'lib/paper_trail/model_config.rb', line 37

def initialize(model_class)
  @model_class = model_class
end

Instance Method Details

#on_createObject

Adds a callback that records a version after a “create” event.



44
45
46
47
48
49
50
# File 'lib/paper_trail/model_config.rb', line 44

def on_create
  @model_class.after_create { |r|
    r.paper_trail.record_create if r.paper_trail.save_version?
  }
  return if @model_class.paper_trail_options[:on].include?(:create)
  @model_class.paper_trail_options[:on] << :create
end

#on_destroy(recording_order = "before") ⇒ Object

Adds a callback that records a version before or after a “destroy” event.



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/paper_trail/model_config.rb', line 55

def on_destroy(recording_order = "before")
  unless %w[after before].include?(recording_order.to_s)
    raise ArgumentError, 'recording order can only be "after" or "before"'
  end

  if recording_order.to_s == "after" && cannot_record_after_destroy?
    raise E_CANNOT_RECORD_AFTER_DESTROY
  end

  @model_class.send(
    "#{recording_order}_destroy",
    lambda do |r|
      return unless r.paper_trail.save_version?
      r.paper_trail.record_destroy(recording_order)
    end
  )

  return if @model_class.paper_trail_options[:on].include?(:destroy)
  @model_class.paper_trail_options[:on] << :destroy
end

#on_touchObject

Adds a callback that records a version after a “touch” event.



101
102
103
104
105
106
107
108
109
# File 'lib/paper_trail/model_config.rb', line 101

def on_touch
  @model_class.after_touch { |r|
    r.paper_trail.record_update(
      force: true,
      in_after_callback: true,
      is_touch: true
    )
  }
end

#on_updateObject

Adds a callback that records a version after an “update” event.



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/paper_trail/model_config.rb', line 79

def on_update
  @model_class.before_save { |r|
    r.paper_trail.reset_timestamp_attrs_for_update_if_needed
  }
  @model_class.after_update { |r|
    if r.paper_trail.save_version?
      r.paper_trail.record_update(
        force: false,
        in_after_callback: true,
        is_touch: false
      )
    end
  }
  @model_class.after_update { |r|
    r.paper_trail.clear_version_instance
  }
  return if @model_class.paper_trail_options[:on].include?(:update)
  @model_class.paper_trail_options[:on] << :update
end

#setup(options = {}) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Set up ‘@model_class` for PaperTrail. Installs callbacks, associations, “class attributes”, instance methods, and more.



114
115
116
117
118
119
120
121
122
123
# File 'lib/paper_trail/model_config.rb', line 114

def setup(options = {})
  options[:on] ||= %i[create update destroy touch]
  options[:on] = Array(options[:on]) # Support single symbol
  @model_class.send :include, ::PaperTrail::Model::InstanceMethods
  setup_options(options)
  setup_associations(options)
  check_presence_of_item_subtype_column(options)
  @model_class.after_rollback { paper_trail.clear_rolled_back_versions }
  setup_callbacks_from_options options[:on]
end

#version_classObject



125
126
127
# File 'lib/paper_trail/model_config.rb', line 125

def version_class
  @_version_class ||= @model_class.version_class_name.constantize
end