bkwld-paper_trail 2.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +10 -0
- data/.travis.yml +5 -0
- data/Gemfile +2 -0
- data/MIT-LICENSE +20 -0
- data/README.md +663 -0
- data/Rakefile +15 -0
- data/lib/generators/paper_trail/USAGE +2 -0
- data/lib/generators/paper_trail/install_generator.rb +20 -0
- data/lib/generators/paper_trail/templates/add_object_changes_column_to_versions.rb +9 -0
- data/lib/generators/paper_trail/templates/create_versions.rb +19 -0
- data/lib/paper_trail.rb +87 -0
- data/lib/paper_trail/config.rb +11 -0
- data/lib/paper_trail/controller.rb +76 -0
- data/lib/paper_trail/has_paper_trail.rb +228 -0
- data/lib/paper_trail/version.rb +159 -0
- data/lib/paper_trail/version_number.rb +3 -0
- data/paper_trail.gemspec +24 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/controllers/application_controller.rb +17 -0
- data/test/dummy/app/controllers/test_controller.rb +5 -0
- data/test/dummy/app/controllers/widgets_controller.rb +23 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/models/animal.rb +4 -0
- data/test/dummy/app/models/article.rb +12 -0
- data/test/dummy/app/models/authorship.rb +5 -0
- data/test/dummy/app/models/book.rb +5 -0
- data/test/dummy/app/models/cat.rb +2 -0
- data/test/dummy/app/models/document.rb +4 -0
- data/test/dummy/app/models/dog.rb +2 -0
- data/test/dummy/app/models/elephant.rb +3 -0
- data/test/dummy/app/models/fluxor.rb +3 -0
- data/test/dummy/app/models/foo_widget.rb +2 -0
- data/test/dummy/app/models/person.rb +5 -0
- data/test/dummy/app/models/post.rb +4 -0
- data/test/dummy/app/models/song.rb +12 -0
- data/test/dummy/app/models/widget.rb +5 -0
- data/test/dummy/app/models/wotsit.rb +4 -0
- data/test/dummy/app/versions/post_version.rb +3 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +45 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +22 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +26 -0
- data/test/dummy/config/environments/production.rb +49 -0
- data/test/dummy/config/environments/test.rb +35 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +3 -0
- data/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb +120 -0
- data/test/dummy/db/schema.rb +103 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/public/javascripts/application.js +2 -0
- data/test/dummy/public/javascripts/controls.js +965 -0
- data/test/dummy/public/javascripts/dragdrop.js +974 -0
- data/test/dummy/public/javascripts/effects.js +1123 -0
- data/test/dummy/public/javascripts/prototype.js +6001 -0
- data/test/dummy/public/javascripts/rails.js +175 -0
- data/test/dummy/public/stylesheets/.gitkeep +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/functional/controller_test.rb +71 -0
- data/test/functional/thread_safety_test.rb +26 -0
- data/test/integration/navigation_test.rb +7 -0
- data/test/paper_trail_test.rb +27 -0
- data/test/support/integration_case.rb +5 -0
- data/test/test_helper.rb +49 -0
- data/test/unit/inheritance_column_test.rb +43 -0
- data/test/unit/model_test.rb +925 -0
- metadata +236 -0
data/Rakefile
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'bundler'
|
|
2
|
+
Bundler::GemHelper.install_tasks
|
|
3
|
+
|
|
4
|
+
require 'rake/testtask'
|
|
5
|
+
|
|
6
|
+
desc 'Test the paper_trail plugin.'
|
|
7
|
+
Rake::TestTask.new(:test) do |t|
|
|
8
|
+
t.libs << 'lib'
|
|
9
|
+
t.libs << 'test'
|
|
10
|
+
t.pattern = 'test/**/*_test.rb'
|
|
11
|
+
t.verbose = false
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
desc 'Default: run unit tests.'
|
|
15
|
+
task :default => :test
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'rails/generators'
|
|
2
|
+
require 'rails/generators/migration'
|
|
3
|
+
require 'rails/generators/active_record/migration'
|
|
4
|
+
|
|
5
|
+
module PaperTrail
|
|
6
|
+
class InstallGenerator < Rails::Generators::Base
|
|
7
|
+
include Rails::Generators::Migration
|
|
8
|
+
extend ActiveRecord::Generators::Migration
|
|
9
|
+
|
|
10
|
+
source_root File.expand_path('../templates', __FILE__)
|
|
11
|
+
class_option :with_changes, :type => :boolean, :default => false, :desc => "Store changeset (diff) with each version"
|
|
12
|
+
|
|
13
|
+
desc 'Generates (but does not run) a migration to add a versions table.'
|
|
14
|
+
|
|
15
|
+
def create_migration_file
|
|
16
|
+
migration_template 'create_versions.rb', 'db/migrate/create_versions.rb'
|
|
17
|
+
migration_template 'add_object_changes_column_to_versions.rb', 'db/migrate/add_object_changes_column_to_versions.rb' if options.with_changes?
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
class CreateVersions < ActiveRecord::Migration
|
|
2
|
+
def self.up
|
|
3
|
+
create_table :versions do |t|
|
|
4
|
+
t.string :item_type, :null => false
|
|
5
|
+
t.integer :item_id, :null => false
|
|
6
|
+
t.string :event, :null => false
|
|
7
|
+
t.string :whodunnit
|
|
8
|
+
t.text :object
|
|
9
|
+
t.text :columns
|
|
10
|
+
t.datetime :created_at
|
|
11
|
+
end
|
|
12
|
+
add_index :versions, [:item_type, :item_id]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.down
|
|
16
|
+
remove_index :versions, [:item_type, :item_id]
|
|
17
|
+
drop_table :versions
|
|
18
|
+
end
|
|
19
|
+
end
|
data/lib/paper_trail.rb
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
require 'singleton'
|
|
2
|
+
require 'yaml'
|
|
3
|
+
|
|
4
|
+
require 'paper_trail/config'
|
|
5
|
+
require 'paper_trail/controller'
|
|
6
|
+
require 'paper_trail/has_paper_trail'
|
|
7
|
+
require 'paper_trail/version'
|
|
8
|
+
|
|
9
|
+
# PaperTrail's module methods can be called in both models and controllers.
|
|
10
|
+
module PaperTrail
|
|
11
|
+
|
|
12
|
+
# Switches PaperTrail on or off.
|
|
13
|
+
def self.enabled=(value)
|
|
14
|
+
PaperTrail.config.enabled = value
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Returns `true` if PaperTrail is on, `false` otherwise.
|
|
18
|
+
# PaperTrail is enabled by default.
|
|
19
|
+
def self.enabled?
|
|
20
|
+
!!PaperTrail.config.enabled
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Returns `true` if PaperTrail is enabled for the request, `false` otherwise.
|
|
24
|
+
#
|
|
25
|
+
# See `PaperTrail::Controller#paper_trail_enabled_for_controller`.
|
|
26
|
+
def self.enabled_for_controller?
|
|
27
|
+
!!paper_trail_store[:request_enabled_for_controller]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Sets whether PaperTrail is enabled or disabled for the current request.
|
|
31
|
+
def self.enabled_for_controller=(value)
|
|
32
|
+
paper_trail_store[:request_enabled_for_controller] = value
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Returns who is reponsible for any changes that occur.
|
|
36
|
+
def self.whodunnit
|
|
37
|
+
paper_trail_store[:whodunnit]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Sets who is responsible for any changes that occur.
|
|
41
|
+
# You would normally use this in a migration or on the console,
|
|
42
|
+
# when working with models directly. In a controller it is set
|
|
43
|
+
# automatically to the `current_user`.
|
|
44
|
+
def self.whodunnit=(value)
|
|
45
|
+
paper_trail_store[:whodunnit] = value
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Returns any information from the controller that you want
|
|
49
|
+
# PaperTrail to store.
|
|
50
|
+
#
|
|
51
|
+
# See `PaperTrail::Controller#info_for_paper_trail`.
|
|
52
|
+
def self.controller_info
|
|
53
|
+
paper_trail_store[:controller_info]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Sets any information from the controller that you want PaperTrail
|
|
57
|
+
# to store. By default this is set automatically by a before filter.
|
|
58
|
+
def self.controller_info=(value)
|
|
59
|
+
paper_trail_store[:controller_info] = value
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
# Thread-safe hash to hold PaperTrail's data.
|
|
66
|
+
# Initializing with needed default values.
|
|
67
|
+
def self.paper_trail_store
|
|
68
|
+
Thread.current[:paper_trail] ||= {
|
|
69
|
+
:request_enabled_for_controller => true
|
|
70
|
+
}
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Returns PaperTrail's configuration object.
|
|
74
|
+
def self.config
|
|
75
|
+
@@config ||= PaperTrail::Config.instance
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
ActiveSupport.on_load(:active_record) do
|
|
82
|
+
include PaperTrail::Model
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
ActiveSupport.on_load(:action_controller) do
|
|
86
|
+
include PaperTrail::Controller
|
|
87
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
module PaperTrail
|
|
2
|
+
module Controller
|
|
3
|
+
|
|
4
|
+
def self.included(base)
|
|
5
|
+
base.before_filter :set_paper_trail_whodunnit
|
|
6
|
+
base.before_filter :set_paper_trail_controller_info
|
|
7
|
+
base.before_filter :set_paper_trail_enabled_for_controller
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
protected
|
|
11
|
+
|
|
12
|
+
# Returns the user who is responsible for any changes that occur.
|
|
13
|
+
# By default this calls `current_user` and returns the result.
|
|
14
|
+
#
|
|
15
|
+
# Override this method in your controller to call a different
|
|
16
|
+
# method, e.g. `current_person`, or anything you like.
|
|
17
|
+
def user_for_paper_trail
|
|
18
|
+
current_user rescue nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Returns any information about the controller or request that you
|
|
22
|
+
# want PaperTrail to store alongside any changes that occur. By
|
|
23
|
+
# default this returns an empty hash.
|
|
24
|
+
#
|
|
25
|
+
# Override this method in your controller to return a hash of any
|
|
26
|
+
# information you need. The hash's keys must correspond to columns
|
|
27
|
+
# in your `versions` table, so don't forget to add any new columns
|
|
28
|
+
# you need.
|
|
29
|
+
#
|
|
30
|
+
# For example:
|
|
31
|
+
#
|
|
32
|
+
# {:ip => request.remote_ip, :user_agent => request.user_agent}
|
|
33
|
+
#
|
|
34
|
+
# The columns `ip` and `user_agent` must exist in your `versions` # table.
|
|
35
|
+
#
|
|
36
|
+
# Use the `:meta` option to `PaperTrail::Model::ClassMethods.has_paper_trail`
|
|
37
|
+
# to store any extra model-level data you need.
|
|
38
|
+
def info_for_paper_trail
|
|
39
|
+
{}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Returns `true` (default) or `false` depending on whether PaperTrail should
|
|
43
|
+
# be active for the current request.
|
|
44
|
+
#
|
|
45
|
+
# Override this method in your controller to specify when PaperTrail should
|
|
46
|
+
# be off.
|
|
47
|
+
def paper_trail_enabled_for_controller
|
|
48
|
+
true
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
# Tells PaperTrail whether versions should be saved in the current request.
|
|
54
|
+
def set_paper_trail_enabled_for_controller
|
|
55
|
+
::PaperTrail.enabled_for_controller = paper_trail_enabled_for_controller
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Tells PaperTrail who is responsible for any changes that occur.
|
|
59
|
+
def set_paper_trail_whodunnit
|
|
60
|
+
::PaperTrail.whodunnit = user_for_paper_trail
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# DEPRECATED: please use `set_paper_trail_whodunnit` instead.
|
|
64
|
+
def set_whodunnit
|
|
65
|
+
logger.warn '[PaperTrail]: the `set_whodunnit` controller method has been deprecated. Please rename to `set_paper_trail_whodunnit`.'
|
|
66
|
+
set_paper_trail_whodunnit
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Tells PaperTrail any information from the controller you want
|
|
70
|
+
# to store alongside any changes that occur.
|
|
71
|
+
def set_paper_trail_controller_info
|
|
72
|
+
::PaperTrail.controller_info = info_for_paper_trail
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
module PaperTrail
|
|
2
|
+
module Model
|
|
3
|
+
|
|
4
|
+
def self.included(base)
|
|
5
|
+
base.send :extend, ClassMethods
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
module ClassMethods
|
|
10
|
+
# Declare this in your model to track every create, update, and destroy. Each version of
|
|
11
|
+
# the model is available in the `versions` association.
|
|
12
|
+
#
|
|
13
|
+
# Options:
|
|
14
|
+
# :on the events to track (optional; defaults to all of them). Set to an array of
|
|
15
|
+
# `:create`, `:update`, `:destroy` as desired.
|
|
16
|
+
# :class_name the name of a custom Version class. This class should inherit from Version.
|
|
17
|
+
# :ignore an array of attributes for which a new `Version` will not be created if only they change.
|
|
18
|
+
# :only inverse of `ignore` - a new `Version` will be created only for these attributes if supplied
|
|
19
|
+
# :meta a hash of extra data to store. You must add a column to the `versions` table for each key.
|
|
20
|
+
# Values are objects or procs (which are called with `self`, i.e. the model with the paper
|
|
21
|
+
# trail). See `PaperTrail::Controller.info_for_paper_trail` for how to store data from
|
|
22
|
+
# the controller.
|
|
23
|
+
# :versions the name to use for the versions association. Default is `:versions`.
|
|
24
|
+
def has_paper_trail(options = {})
|
|
25
|
+
# Lazily include the instance methods so we don't clutter up
|
|
26
|
+
# any more ActiveRecord models than we have to.
|
|
27
|
+
send :include, InstanceMethods
|
|
28
|
+
|
|
29
|
+
# The version this instance was reified from.
|
|
30
|
+
attr_accessor :version
|
|
31
|
+
|
|
32
|
+
class_attribute :version_class_name
|
|
33
|
+
self.version_class_name = options[:class_name] || 'Version'
|
|
34
|
+
|
|
35
|
+
class_attribute :ignore
|
|
36
|
+
self.ignore = ([options[:ignore]].flatten.compact || []).map &:to_s
|
|
37
|
+
|
|
38
|
+
class_attribute :only
|
|
39
|
+
self.only = ([options[:only]].flatten.compact || []).map &:to_s
|
|
40
|
+
|
|
41
|
+
class_attribute :meta
|
|
42
|
+
self.meta = options[:meta] || {}
|
|
43
|
+
|
|
44
|
+
class_attribute :track_columns
|
|
45
|
+
self.track_columns = options[:track_columns] || true
|
|
46
|
+
|
|
47
|
+
class_attribute :ignored_columns
|
|
48
|
+
self.ignored_columns = options[:ignored_columns] || ['id', 'updated_at', 'created_at']
|
|
49
|
+
|
|
50
|
+
class_attribute :paper_trail_enabled_for_model
|
|
51
|
+
self.paper_trail_enabled_for_model = true
|
|
52
|
+
|
|
53
|
+
class_attribute :versions_association_name
|
|
54
|
+
self.versions_association_name = options[:versions] || :versions
|
|
55
|
+
|
|
56
|
+
has_many self.versions_association_name,
|
|
57
|
+
:class_name => version_class_name,
|
|
58
|
+
:as => :item,
|
|
59
|
+
:order => "created_at ASC, #{self.version_class_name.constantize.primary_key} ASC"
|
|
60
|
+
|
|
61
|
+
after_create :record_create if !options[:on] || options[:on].include?(:create)
|
|
62
|
+
before_update :record_update if !options[:on] || options[:on].include?(:update)
|
|
63
|
+
after_destroy :record_destroy if !options[:on] || options[:on].include?(:destroy)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Switches PaperTrail off for this class.
|
|
67
|
+
def paper_trail_off
|
|
68
|
+
self.paper_trail_enabled_for_model = false
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Switches PaperTrail on for this class.
|
|
72
|
+
def paper_trail_on
|
|
73
|
+
self.paper_trail_enabled_for_model = true
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Wrap the following methods in a module so we can include them only in the
|
|
78
|
+
# ActiveRecord models that declare `has_paper_trail`.
|
|
79
|
+
module InstanceMethods
|
|
80
|
+
# Returns true if this instance is the current, live one;
|
|
81
|
+
# returns false if this instance came from a previous version.
|
|
82
|
+
def live?
|
|
83
|
+
version.nil?
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Returns who put the object into its current state.
|
|
87
|
+
def originator
|
|
88
|
+
version_class.with_item_keys(self.class.name, id).last.try :whodunnit
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Returns the object (not a Version) as it was at the given timestamp.
|
|
92
|
+
def version_at(timestamp, reify_options={})
|
|
93
|
+
# Because a version stores how its object looked *before* the change,
|
|
94
|
+
# we need to look for the first version created *after* the timestamp.
|
|
95
|
+
version = send(self.class.versions_association_name).after(timestamp).first
|
|
96
|
+
version ? version.reify(reify_options) : self
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Returns the object (not a Version) as it was most recently.
|
|
100
|
+
def previous_version
|
|
101
|
+
preceding_version = version ? version.previous : send(self.class.versions_association_name).last
|
|
102
|
+
preceding_version.try :reify
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Returns the object (not a Version) as it became next.
|
|
106
|
+
def next_version
|
|
107
|
+
# NOTE: if self (the item) was not reified from a version, i.e. it is the
|
|
108
|
+
# "live" item, we return nil. Perhaps we should return self instead?
|
|
109
|
+
subsequent_version = version ? version.next : nil
|
|
110
|
+
subsequent_version.reify if subsequent_version
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Executes the given method or block without creating a new version.
|
|
114
|
+
def without_versioning(method = nil)
|
|
115
|
+
paper_trail_was_enabled = self.paper_trail_enabled_for_model
|
|
116
|
+
self.class.paper_trail_off
|
|
117
|
+
method ? method.to_proc.call(self) : yield
|
|
118
|
+
ensure
|
|
119
|
+
self.class.paper_trail_on if paper_trail_was_enabled
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
private
|
|
123
|
+
|
|
124
|
+
def version_class
|
|
125
|
+
version_class_name.constantize
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def record_create
|
|
129
|
+
if switched_on?
|
|
130
|
+
send(self.class.versions_association_name).create merge_metadata(:event => 'create', :whodunnit => PaperTrail.whodunnit)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def record_update
|
|
135
|
+
if switched_on? && changed_notably?
|
|
136
|
+
data = {
|
|
137
|
+
:event => 'update',
|
|
138
|
+
:object => object_to_string(item_before_change),
|
|
139
|
+
:whodunnit => PaperTrail.whodunnit
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if version_class.column_names.include? 'object_changes'
|
|
143
|
+
# The double negative (reject, !include?) preserves the hash structure of self.changes.
|
|
144
|
+
data[:object_changes] = self.changes.reject do |key, value|
|
|
145
|
+
!notably_changed.include?(key)
|
|
146
|
+
end.to_yaml
|
|
147
|
+
end
|
|
148
|
+
send(self.class.versions_association_name).build merge_metadata(data)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def record_destroy
|
|
153
|
+
if switched_on? and not new_record?
|
|
154
|
+
version_class.create merge_metadata(:item_id => self.id,
|
|
155
|
+
:item_type => self.class.base_class.name,
|
|
156
|
+
:event => 'destroy',
|
|
157
|
+
:object => object_to_string(item_before_change),
|
|
158
|
+
:whodunnit => PaperTrail.whodunnit)
|
|
159
|
+
end
|
|
160
|
+
send(self.class.versions_association_name).send :load_target
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def merge_metadata(data)
|
|
164
|
+
# First we merge the model-level metadata in `meta`.
|
|
165
|
+
meta.each do |k,v|
|
|
166
|
+
data[k] =
|
|
167
|
+
if v.respond_to?(:call)
|
|
168
|
+
v.call(self)
|
|
169
|
+
elsif v.is_a?(Symbol) && respond_to?(v)
|
|
170
|
+
send(v)
|
|
171
|
+
else
|
|
172
|
+
v
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
# Second we merge any extra data from the controller (if available).
|
|
176
|
+
data.merge(PaperTrail.controller_info || {})
|
|
177
|
+
|
|
178
|
+
column_changes = {}
|
|
179
|
+
change_info = changes.dup
|
|
180
|
+
change_info.reject! { |column_name, change_values|
|
|
181
|
+
self.class.ignored_columns.include?(column_name)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
change_info.each do |column_name, change_values|
|
|
185
|
+
column_changes[column_name.to_sym] = {
|
|
186
|
+
:after => change_values[1],
|
|
187
|
+
:before => change_values[0]
|
|
188
|
+
}
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
data.merge(:columns => column_changes)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def item_before_change
|
|
195
|
+
previous = self.dup
|
|
196
|
+
# `dup` clears timestamps so we add them back.
|
|
197
|
+
all_timestamp_attributes.each do |column|
|
|
198
|
+
previous[column] = send(column) if respond_to?(column) && !send(column).nil?
|
|
199
|
+
end
|
|
200
|
+
previous.tap do |prev|
|
|
201
|
+
prev.id = id
|
|
202
|
+
changed_attributes.each { |attr, before| prev[attr] = before }
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def object_to_string(object)
|
|
207
|
+
object.attributes.to_yaml
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def changed_notably?
|
|
211
|
+
notably_changed.any?
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def notably_changed
|
|
215
|
+
self.class.only.empty? ? changed_and_not_ignored : (changed_and_not_ignored & self.class.only)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def changed_and_not_ignored
|
|
219
|
+
changed - self.class.ignore
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def switched_on?
|
|
223
|
+
PaperTrail.enabled? && PaperTrail.enabled_for_controller? && self.class.paper_trail_enabled_for_model
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
end
|
|
228
|
+
end
|