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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0c0a48f3d22566d6b3ce0e11581f26e349927a31
4
- data.tar.gz: 9f236ae8f678bdc46e2796b203d2de2485c6c466
3
+ metadata.gz: 0db78111e08142c80966e125fefc9b785bf750b3
4
+ data.tar.gz: 5ce3fa303c8e88475b20f42643fdaf7b6761fc6e
5
5
  SHA512:
6
- metadata.gz: e8c63536e1e473aaa7edab32adfcc79c5ba25ff23a0851c1414c9445e8cbe29f57eee6bc265c4faf0675b92f70918ef7b7cda777865fd2da4bfac3761a7afb41
7
- data.tar.gz: 18e39e2afe1ccca46ff6f4c39ef76471a99d68bb23f1efd92675ad11c04fd1cf04a559ad5a41be67ae193b21b1de1b319be6664e56e1f9bcc7d0e30980a1eaca
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
@@ -0,0 +1,6 @@
1
+ # 1.0.0
2
+ * Interface changed: call `automatically_log_changes` in your model instead of setting up an `after_initialize` callback.
3
+ * `automatically_log_changes` now supports list of columns to exclude.
4
+
5
+ # 0.0.2
6
+ * Birthday
data/Gemfile CHANGED
@@ -1,4 +1,8 @@
1
1
  source "http://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in changes_are_logged.gemspec
4
- gemspec
4
+ gemspec
5
+
6
+ group :development, :test do
7
+ gem 'pry-byebug'
8
+ end
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
- USAGE
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
- after_initialize :automatically_log_changes
13
+ automatically_log_changes
14
14
  end
15
+ ```
15
16
 
16
- Then anytime that object is modified, a new entry in the change_logs table will be added:
17
- <pre><code>
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
- </code></pre>
26
-
27
- ASSUMPTIONS
28
- ===========
29
-
30
- The method 'current_user' is defined by your app, and returns the User that is currently logged in.
31
-
32
- TODO
33
- ====
34
-
35
- Add migration for creation of the change_logs table. For now, here is the schema:
36
- <pre><code>
37
- mysql> desc change_logs;
38
- +----------------+--------------+------+-----+---------+----------------+
39
- | Field | Type | Null | Key | Default | Extra |
40
- +----------------+--------------+------+-----+---------+----------------+
41
- | id | int(11) | NO | PRI | NULL | auto_increment |
42
- | target_id | int(11) | YES | | NULL | |
43
- | target_type | varchar(255) | YES | | NULL | |
44
- | changes_logged | text | YES | | NULL | |
45
- | comments | text | YES | | NULL | |
46
- | user_id | int(11) | YES | | NULL | |
47
- | created_at | datetime | YES | | NULL | |
48
- +----------------+--------------+------+-----+---------+----------------+
49
- </code></pre>
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
+ ```
@@ -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 = ["nyu", "jdb", "cef", "ejk"]
9
- s.email = ""
10
- s.homepage = ""
11
- s.summary = %q{Log changes for record keeping}
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', '2.7.0'
23
- s.add_development_dependency 'activerecord', '3.0.11'
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
@@ -1,3 +1,3 @@
1
1
  module ChangesAreLogged
2
- VERSION = "0.0.2"
2
+ VERSION = '1.0.0'
3
3
  end
@@ -1,4 +1,4 @@
1
- require "changes_are_logged/version"
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 self.new_record?
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 self.changed? || !@change_comments.blank?
25
- @changes_logged = self.changes
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
- def automatically_log_changes
48
- @log_changes = true
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
@@ -13,23 +13,56 @@ describe 'ChangeLog' do
13
13
  end
14
14
  end
15
15
 
16
- context 'Making changes to a game with change comments' do
17
- before do
18
- @game = Game.create
19
- @original_change_logs_size = @game.change_logs.size
20
- @original_name = @game.name
21
- @original_slug = @game.url_slug
22
- @game.name = 'shazam!'
23
- @game.url_slug = 'shazam'
24
- @comment = 'switching to cooler name'
25
- @game.change_comments = @comment
26
- @game.save!
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 'should record the change comments in the change_logs' do
30
- @game.reload.change_logs.size.should == @original_change_logs_size + 1
31
- @game.change_logs.last.changes_logged.should == {"name" => [@original_name, "shazam!"], "url_slug"=>[@original_slug, "shazam"]}
32
- @game.change_logs.last.comments.should == @comment
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' #test_data'
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
- after_initialize :automatically_log_changes
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.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
- - nyu
8
- - jdb
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: rspec-rails
15
+ name: activerecord
18
16
  requirement: !ruby/object:Gem::Requirement
19
17
  requirements:
20
- - - '='
18
+ - - ">="
21
19
  - !ruby/object:Gem::Version
22
- version: 2.7.0
23
- type: :development
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: 2.7.0
27
+ version: '4.0'
30
28
  - !ruby/object:Gem::Dependency
31
- name: activerecord
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.11
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.11
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.4
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.4
58
- description: change_log
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: changes_are_logged
94
- rubygems_version: 2.2.3
94
+ rubyforge_project:
95
+ rubygems_version: 2.5.2
95
96
  signing_key:
96
97
  specification_version: 4
97
- summary: Log changes for record keeping
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