changes_are_logged 0.0.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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