changes_are_logged 0.0.2 → 1.0.0
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.
- checksums.yaml +4 -4
- data/.ruby-version +1 -0
- data/.travis.yml +14 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile +5 -1
- data/README.md +47 -31
- data/changes_are_logged.gemspec +9 -11
- data/lib/changes_are_logged/change_log.rb +7 -7
- data/lib/changes_are_logged/version.rb +1 -1
- data/lib/changes_are_logged.rb +26 -8
- data/spec/change_log_spec.rb +48 -15
- data/spec/spec_helper.rb +3 -2
- data/spec/support/database_helpers.rb +23 -2
- metadata +27 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0db78111e08142c80966e125fefc9b785bf750b3
|
4
|
+
data.tar.gz: 5ce3fa303c8e88475b20f42643fdaf7b6761fc6e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2dffbcd9dd09a96c0808d43616726758749a6c2c6a38b70ebeff2ec69a9259fd804e68b7e1870d509b547b7381afdc73463988f90eee52c5dffac8878ab3bfd3
|
7
|
+
data.tar.gz: ad110b572a752c1163e0f1cb7a058391a9efe612325307708b40433053eddcfce6d2f5e7e207ade2881842396a7abacb2b29ef09f8e4cb83902038e9d8aac900
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.3.3
|
data/.travis.yml
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.3.3
|
4
|
+
sudo: false
|
5
|
+
cache:
|
6
|
+
- bundler
|
7
|
+
notifications:
|
8
|
+
email: false
|
9
|
+
script: bundle exec rspec
|
10
|
+
env:
|
11
|
+
- RAILS_VERSION='~> 4.0.0'
|
12
|
+
- RAILS_VERSION='~> 4.1.0'
|
13
|
+
- RAILS_VERSION='~> 4.2.0'
|
14
|
+
- RAILS_VERSION='~> 5.0.0'
|
data/CHANGELOG.md
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -3,18 +3,20 @@ Changes Are Logged
|
|
3
3
|
|
4
4
|
This is a simple way to record when a ActiveRecord model is modified.
|
5
5
|
|
6
|
-
|
7
|
-
=====
|
6
|
+
## Usage
|
8
7
|
|
9
|
-
Hook changes_are_logged into your ActiveRecord model:
|
8
|
+
Hook changes_are_logged into your ActiveRecord model by calling the `automatically_log_changes` method:
|
10
9
|
|
10
|
+
```ruby
|
11
11
|
class Game < ActiveRecord::Base
|
12
12
|
include ChangesAreLogged
|
13
|
-
|
13
|
+
automatically_log_changes
|
14
14
|
end
|
15
|
+
```
|
15
16
|
|
16
|
-
Then
|
17
|
-
|
17
|
+
Then any time that object is modified, a new entry in the `change_logs` table will be added:
|
18
|
+
|
19
|
+
```
|
18
20
|
> game.change_logs
|
19
21
|
=> []
|
20
22
|
> game.update_attribute(:name, 'Wombats Rule')
|
@@ -22,28 +24,42 @@ Then anytime that object is modified, a new entry in the change_logs table will
|
|
22
24
|
> game.change_logs
|
23
25
|
=> [#<ChangeLog id: 442, target_id: 65, target_type: "Game", changes_logged: {"name"=>["Old Name", "Wombats Rule"]}, comments: nil, user_id: 68, created_at: "2011-11-16 00:01:04">]
|
24
26
|
>
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
27
|
+
```
|
28
|
+
|
29
|
+
You can alter the logged values by passing a block to `automatically_log_changes`, which can be handy if the column contains a complex Ruby object (think Carrierwave uploaders, etc). The block expects you to return a two-element array with the modified old and new values:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
class Game < ActiveRecord::Base
|
33
|
+
# example carrierwave uploader attached to the 'thumbnail' column
|
34
|
+
mount_uploader :thumbnail, MyApp::MyThumbnailUploader
|
35
|
+
|
36
|
+
include ChangesAreLogged
|
37
|
+
automatically_log_changes do |attribute, old_value, new_value|
|
38
|
+
if attribute == 'thumbnail'
|
39
|
+
[old_value.filename, new_value.filename] # or something similar
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
Now the value of the `thumbnail` column won't be included if it changes. The text "Attribute changed, but value has been filtered." will be logged instead.
|
46
|
+
|
47
|
+
## Assumptions
|
48
|
+
|
49
|
+
The method `current_user` is defined by your app, and returns the user instance that is currently logged in.
|
50
|
+
|
51
|
+
## Setup
|
52
|
+
|
53
|
+
Add migration for creation of the `change_logs` table. Here's the important bit:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
create_table :change_logs do |t|
|
57
|
+
t.column :target_id, :integer
|
58
|
+
t.column :target_type, :string
|
59
|
+
t.column :changes_logged, :text
|
60
|
+
t.column :comments, :text
|
61
|
+
t.column :user_id, :integer
|
62
|
+
t.column :user_is_staff, :boolean
|
63
|
+
t.timestamps
|
64
|
+
end
|
65
|
+
```
|
data/changes_are_logged.gemspec
CHANGED
@@ -5,21 +5,19 @@ require "changes_are_logged/version"
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = "changes_are_logged"
|
7
7
|
s.version = ChangesAreLogged::VERSION
|
8
|
-
s.authors = [
|
9
|
-
s.
|
10
|
-
s.
|
11
|
-
s.
|
12
|
-
s.description = %q{change_log}
|
13
|
-
|
14
|
-
s.rubyforge_project = "changes_are_logged"
|
8
|
+
s.authors = ['Lawrence Wang', 'Cameron Dutro']
|
9
|
+
s.homepage = 'https://github.com/lumoslabs/changes_are_logged'
|
10
|
+
s.summary = 'Tracks changes to your activerecord models'
|
11
|
+
s.description = 'Tracks changes to your activerecord models'
|
15
12
|
|
16
13
|
s.files = `git ls-files`.split("\n")
|
17
14
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
15
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
19
16
|
s.require_paths = ["lib"]
|
20
17
|
|
18
|
+
s.add_dependency 'activerecord', ENV.fetch('RAILS_VERSION', '>= 4.0')
|
19
|
+
|
21
20
|
# specify any dependencies here instead of Gemfile:
|
22
|
-
s.add_development_dependency 'rspec-rails', '
|
23
|
-
s.add_development_dependency '
|
24
|
-
s.add_development_dependency 'sqlite3', '1.3.4'
|
21
|
+
s.add_development_dependency 'rspec-rails', '~> 3.0'
|
22
|
+
s.add_development_dependency 'sqlite3', '~> 1.3'
|
25
23
|
end
|
@@ -35,21 +35,21 @@ class ChangeLog < ActiveRecord::Base
|
|
35
35
|
return nil unless user_id
|
36
36
|
user_is_staff ? StaffUser.find(user_id) : User.find(user_id)
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
def has_changes?
|
40
40
|
changes_logged && changes_logged.any?
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
def pretty_change_hashes
|
44
44
|
changes_logged.map do |k, (from, to)|
|
45
45
|
{
|
46
|
-
:key => k,
|
47
|
-
:from => self.class.pretty_value(from),
|
46
|
+
:key => k,
|
47
|
+
:from => self.class.pretty_value(from),
|
48
48
|
:to => self.class.pretty_value(to)
|
49
49
|
}
|
50
50
|
end
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
def self.pretty_value(v)
|
54
54
|
if v.nil?
|
55
55
|
"(nil)"
|
@@ -59,5 +59,5 @@ class ChangeLog < ActiveRecord::Base
|
|
59
59
|
v.pretty_inspect
|
60
60
|
end
|
61
61
|
end
|
62
|
-
|
63
|
-
end
|
62
|
+
|
63
|
+
end
|
data/lib/changes_are_logged.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require 'changes_are_logged/version'
|
2
2
|
require 'changes_are_logged/change_log'
|
3
3
|
|
4
4
|
module ChangesAreLogged
|
@@ -17,12 +17,23 @@ module ChangesAreLogged
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
if
|
20
|
+
if new_record?
|
21
21
|
@change_comments = "new record" if @change_comments.blank?
|
22
22
|
@changes_logged = {}
|
23
23
|
save_change_log
|
24
|
-
elsif
|
25
|
-
@changes_logged =
|
24
|
+
elsif changed? || !@change_comments.blank?
|
25
|
+
@changes_logged = HashWithIndifferentAccess.new
|
26
|
+
|
27
|
+
if log_changes_callback
|
28
|
+
changes.each do |attribute, (old_value, new_value)|
|
29
|
+
@changes_logged[attribute] = log_changes_callback.call(
|
30
|
+
attribute, old_value, new_value
|
31
|
+
)
|
32
|
+
end
|
33
|
+
else
|
34
|
+
@changes_logged.merge!(changes)
|
35
|
+
end
|
36
|
+
|
26
37
|
@changes_logged.delete("updated_at")
|
27
38
|
save_change_log
|
28
39
|
end
|
@@ -30,8 +41,8 @@ module ChangesAreLogged
|
|
30
41
|
|
31
42
|
def save_change_log
|
32
43
|
self.change_logs << ChangeLog.new(
|
33
|
-
:changes_logged => @changes_logged,
|
34
|
-
:user_id => @modifying_user_id,
|
44
|
+
:changes_logged => @changes_logged,
|
45
|
+
:user_id => @modifying_user_id,
|
35
46
|
:comments => @change_comments,
|
36
47
|
:user_is_staff => @modifying_user_is_staff
|
37
48
|
)
|
@@ -43,18 +54,25 @@ module ChangesAreLogged
|
|
43
54
|
def attribute_change(attr)
|
44
55
|
[changed_attributes[attr], __send__(:read_attribute, attr)] if attribute_changed?(attr)
|
45
56
|
end
|
57
|
+
end
|
46
58
|
|
47
|
-
|
48
|
-
|
59
|
+
module ClassMethods
|
60
|
+
def automatically_log_changes(&block)
|
61
|
+
after_initialize -> do
|
62
|
+
@log_changes = true
|
63
|
+
@log_changes_callback = block
|
64
|
+
end
|
49
65
|
end
|
50
66
|
end
|
51
67
|
|
52
68
|
def self.included(klass)
|
53
69
|
klass.class_eval do
|
54
70
|
include InstanceMethods
|
71
|
+
extend ClassMethods
|
55
72
|
attr_accessor :modifying_user_id
|
56
73
|
attr_accessor :change_comments
|
57
74
|
attr_accessor :log_changes
|
75
|
+
attr_reader :log_changes_callback
|
58
76
|
before_save :log_it
|
59
77
|
has_many :change_logs, :as => :target
|
60
78
|
end
|
data/spec/change_log_spec.rb
CHANGED
@@ -13,23 +13,56 @@ describe 'ChangeLog' do
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
16
|
+
shared_examples 'a change-logging game model' do |game_class|
|
17
|
+
let(:game) { game_class.create.tap { |g| g.change_comments = comment } }
|
18
|
+
let(:comment) { 'switching to cooler name' }
|
19
|
+
let(:new_attributes) { { name: 'shazam!', url_slug: 'shazam' } }
|
20
|
+
let(:change_log) { game.change_logs.last }
|
21
|
+
|
22
|
+
it 'creates a new change log record with the correct attributes' do
|
23
|
+
original_attributes = game.attributes
|
24
|
+
|
25
|
+
expect { game.update_attributes(new_attributes) }.to(
|
26
|
+
change { game.change_logs.count }.from(1).to(2)
|
27
|
+
)
|
28
|
+
|
29
|
+
expect(change_log.changes_logged).to eq(
|
30
|
+
'name' => [original_attributes[:name], new_attributes[:name]],
|
31
|
+
'url_slug' => [original_attributes[:url_slug], new_attributes[:url_slug]]
|
32
|
+
)
|
27
33
|
end
|
28
34
|
|
29
|
-
it '
|
30
|
-
|
31
|
-
|
32
|
-
|
35
|
+
it 'includes the given comment in the change log record' do
|
36
|
+
game.update_attributes(new_attributes)
|
37
|
+
expect(change_log.comments).to eq(comment)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'with a standard game model' do
|
42
|
+
it_behaves_like 'a change-logging game model', Game
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'with an STI model' do
|
46
|
+
it_behaves_like 'a change-logging game model', SubclassedGame
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'with a model that modifies certain logged values' do
|
50
|
+
let(:game) { OtherGame.create.tap { |g| g.change_comments = comment } }
|
51
|
+
let(:comment) { 'switching to cooler name' }
|
52
|
+
let(:new_attributes) { { name: 'shazam!', url_slug: 'shazam' } }
|
53
|
+
let(:change_log) { game.change_logs.last }
|
54
|
+
|
55
|
+
it 'creates a new change log record with modified column values' do
|
56
|
+
original_attributes = game.attributes
|
57
|
+
|
58
|
+
expect { game.update_attributes(new_attributes) }.to(
|
59
|
+
change { game.change_logs.count }.from(1).to(2)
|
60
|
+
)
|
61
|
+
|
62
|
+
expect(change_log.changes_logged).to eq(
|
63
|
+
'name' => ['old_', 'new_shazam!'],
|
64
|
+
'url_slug' => [original_attributes[:url_slug], 'shazam']
|
65
|
+
)
|
33
66
|
end
|
34
67
|
end
|
35
68
|
|
data/spec/spec_helper.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'bundler/setup'
|
3
3
|
require 'active_record'
|
4
|
+
require 'pry-byebug'
|
4
5
|
|
5
6
|
require 'changes_are_logged'
|
6
7
|
|
7
|
-
require 'support/database_helpers'
|
8
|
+
require 'support/database_helpers'
|
8
9
|
|
9
10
|
RSpec.configure do |config|
|
10
11
|
config.include ChangesAreLogged::Spec::DatabaseHelpers
|
@@ -17,4 +18,4 @@ RSpec.configure do |config|
|
|
17
18
|
config.after do
|
18
19
|
teardown_db
|
19
20
|
end
|
20
|
-
end
|
21
|
+
end
|
@@ -20,6 +20,13 @@ module ChangesAreLogged
|
|
20
20
|
t.column :created_at, :datetime
|
21
21
|
t.column :updated_at, :datetime
|
22
22
|
end
|
23
|
+
|
24
|
+
create_table :other_games do |t|
|
25
|
+
t.column :name, :string
|
26
|
+
t.column :url_slug, :string
|
27
|
+
t.column :created_at, :datetime
|
28
|
+
t.column :updated_at, :datetime
|
29
|
+
end
|
23
30
|
end
|
24
31
|
end
|
25
32
|
|
@@ -31,9 +38,23 @@ module ChangesAreLogged
|
|
31
38
|
|
32
39
|
class ::Game < ActiveRecord::Base
|
33
40
|
include ChangesAreLogged
|
34
|
-
|
41
|
+
automatically_log_changes
|
42
|
+
end
|
43
|
+
|
44
|
+
class ::OtherGame < ActiveRecord::Base
|
45
|
+
include ChangesAreLogged
|
46
|
+
automatically_log_changes do |attribute, old_value, new_value|
|
47
|
+
if attribute == 'name'
|
48
|
+
["old_#{old_value}", "new_#{new_value}"]
|
49
|
+
else
|
50
|
+
[old_value, new_value]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class ::SubclassedGame < Game
|
35
56
|
end
|
36
57
|
end
|
37
58
|
|
38
59
|
end
|
39
|
-
end
|
60
|
+
end
|
metadata
CHANGED
@@ -1,67 +1,68 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: changes_are_logged
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
8
|
-
-
|
9
|
-
- cef
|
10
|
-
- ejk
|
7
|
+
- Lawrence Wang
|
8
|
+
- Cameron Dutro
|
11
9
|
autorequire:
|
12
10
|
bindir: bin
|
13
11
|
cert_chain: []
|
14
12
|
date: 2016-12-20 00:00:00.000000000 Z
|
15
13
|
dependencies:
|
16
14
|
- !ruby/object:Gem::Dependency
|
17
|
-
name:
|
15
|
+
name: activerecord
|
18
16
|
requirement: !ruby/object:Gem::Requirement
|
19
17
|
requirements:
|
20
|
-
- -
|
18
|
+
- - ">="
|
21
19
|
- !ruby/object:Gem::Version
|
22
|
-
version:
|
23
|
-
type: :
|
20
|
+
version: '4.0'
|
21
|
+
type: :runtime
|
24
22
|
prerelease: false
|
25
23
|
version_requirements: !ruby/object:Gem::Requirement
|
26
24
|
requirements:
|
27
|
-
- -
|
25
|
+
- - ">="
|
28
26
|
- !ruby/object:Gem::Version
|
29
|
-
version:
|
27
|
+
version: '4.0'
|
30
28
|
- !ruby/object:Gem::Dependency
|
31
|
-
name:
|
29
|
+
name: rspec-rails
|
32
30
|
requirement: !ruby/object:Gem::Requirement
|
33
31
|
requirements:
|
34
|
-
- -
|
32
|
+
- - "~>"
|
35
33
|
- !ruby/object:Gem::Version
|
36
|
-
version: 3.0
|
34
|
+
version: '3.0'
|
37
35
|
type: :development
|
38
36
|
prerelease: false
|
39
37
|
version_requirements: !ruby/object:Gem::Requirement
|
40
38
|
requirements:
|
41
|
-
- -
|
39
|
+
- - "~>"
|
42
40
|
- !ruby/object:Gem::Version
|
43
|
-
version: 3.0
|
41
|
+
version: '3.0'
|
44
42
|
- !ruby/object:Gem::Dependency
|
45
43
|
name: sqlite3
|
46
44
|
requirement: !ruby/object:Gem::Requirement
|
47
45
|
requirements:
|
48
|
-
- -
|
46
|
+
- - "~>"
|
49
47
|
- !ruby/object:Gem::Version
|
50
|
-
version: 1.3
|
48
|
+
version: '1.3'
|
51
49
|
type: :development
|
52
50
|
prerelease: false
|
53
51
|
version_requirements: !ruby/object:Gem::Requirement
|
54
52
|
requirements:
|
55
|
-
- -
|
53
|
+
- - "~>"
|
56
54
|
- !ruby/object:Gem::Version
|
57
|
-
version: 1.3
|
58
|
-
description:
|
59
|
-
email:
|
55
|
+
version: '1.3'
|
56
|
+
description: Tracks changes to your activerecord models
|
57
|
+
email:
|
60
58
|
executables: []
|
61
59
|
extensions: []
|
62
60
|
extra_rdoc_files: []
|
63
61
|
files:
|
64
62
|
- ".gitignore"
|
63
|
+
- ".ruby-version"
|
64
|
+
- ".travis.yml"
|
65
|
+
- CHANGELOG.md
|
65
66
|
- Gemfile
|
66
67
|
- README.md
|
67
68
|
- Rakefile
|
@@ -72,7 +73,7 @@ files:
|
|
72
73
|
- spec/change_log_spec.rb
|
73
74
|
- spec/spec_helper.rb
|
74
75
|
- spec/support/database_helpers.rb
|
75
|
-
homepage:
|
76
|
+
homepage: https://github.com/lumoslabs/changes_are_logged
|
76
77
|
licenses: []
|
77
78
|
metadata: {}
|
78
79
|
post_install_message:
|
@@ -90,11 +91,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
90
91
|
- !ruby/object:Gem::Version
|
91
92
|
version: '0'
|
92
93
|
requirements: []
|
93
|
-
rubyforge_project:
|
94
|
-
rubygems_version: 2.2
|
94
|
+
rubyforge_project:
|
95
|
+
rubygems_version: 2.5.2
|
95
96
|
signing_key:
|
96
97
|
specification_version: 4
|
97
|
-
summary:
|
98
|
+
summary: Tracks changes to your activerecord models
|
98
99
|
test_files:
|
99
100
|
- spec/change_log_spec.rb
|
100
101
|
- spec/spec_helper.rb
|