mongoid-audit_log 0.0.1

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 ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OWYyMWJjOWFkN2ExYzA0ZWNhODkzZjQ2MTIxZDcxODNmMjNkN2QwOQ==
5
+ data.tar.gz: !binary |-
6
+ MjJkOTRiNzcwNTI1NTg3NzI2ZDJjNDFlNjA5ZGQwMTM0OTI1YjdlMg==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NzY2ODJiMmQ3YmQ2MThlYjhiOWJmMWFkN2JkOGVhYjRjYjQ2MmRjMjkzY2E1
10
+ MjM3Y2Q2MGVlZjQzZmQ5MDg3OGUyZTY3MDA0OTA0OWIxNmFkNTA4ZTY3OWQw
11
+ MTM5Yzk3YmVjMDYwNDBhMDg3NTc0MzJjODE0NjcyZWM3MWQ2ZTA=
12
+ data.tar.gz: !binary |-
13
+ Nzk0MDY1MGZmYzdmZjIzZjI5ZjQ4ZDJjNjIxNTM2YjBiMGVmMTk1YTliYzY1
14
+ NmY0ZmJmNTk5NjM3NmYyZDNmNTQxOTQ2NjYzYTJlNmZmZjBlOTc4YTcxMzky
15
+ YzY2ODQxODgyNDI5MGRjM2M5MTk0N2RmZjQ5Mjc4OTkxMWI0ZTY=
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --failure-exit-code 0
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ group :test do
5
+ gem 'rspec', '2.14.1'
6
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 bcrouse
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,114 @@
1
+ # Mongoid::AuditLog
2
+
3
+ Frustrated with the other options for this, I wrote this gem to handle most basic audit logging for Mongoid. It is intended to be stupidly simple, and offers no fancy functionality.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'mongoid-audit_log'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install mongoid-audit_log
18
+
19
+ ## Usage
20
+
21
+ ### Recording Activity
22
+
23
+ Include the `Mongoid::AuditLog` module into your model.
24
+
25
+ ```ruby
26
+ class Model
27
+ include Mongoid::Document
28
+ include Mongoid::AuditLog
29
+ field :name
30
+ end
31
+ ```
32
+
33
+ This will not enable logging by itself, only changes made within the block passed to the record method will be saved.
34
+
35
+ ```ruby
36
+ Mongoid::AuditLog.record do
37
+ Model.create!
38
+ end
39
+ ```
40
+
41
+ If you want to log the user who made the change, pass that user to the record method:
42
+
43
+ ```ruby
44
+ Mongoid::AuditLog.record(current_user) do
45
+ Model.create!
46
+ end
47
+ ```
48
+
49
+ A basic implementation in a Rails app might look something like:
50
+
51
+ ```ruby
52
+ class ApplicationController < ActionController::Base
53
+ around_filter :audit_log
54
+
55
+ def current_user
56
+ @current_user ||= User.find(session[:user_id])
57
+ end
58
+
59
+ private
60
+
61
+ def audit_log
62
+ Mongoid::AuditLog.record(current_user) do
63
+ yield
64
+ end
65
+ end
66
+ end
67
+ ```
68
+
69
+ ### Viewing Activity
70
+
71
+ When an audited model is changed, it will create a record of the `Mongoid::AuditLog::Entry` class.
72
+ Each class responds to some query methods:
73
+
74
+ ```ruby
75
+ Mongoid::AuditLog.record do
76
+ model = Model.create!
77
+ module.update_attributes(:name => 'model')
78
+ end
79
+
80
+ model.audit_log_entries.length == 2
81
+
82
+ model.audit_log_entries.first.create? # => true
83
+ model.audit_log_entries.first.update? # => false
84
+ model.audit_log_entries.first.destroy? # => false
85
+
86
+ model.audit_log_entries.second.create? # => false
87
+ model.audit_log_entries.second.update? # => true
88
+ model.audit_log_entries.second.destroy? # => false
89
+
90
+ # And on update you have the tracked changes
91
+ model.audit_log_entries.second.tracked_changes.should == { 'name' => [nil, 'model'] }
92
+ ```
93
+
94
+ There are also some built-in scopes (from the tests):
95
+
96
+ ```ruby
97
+ create = Entry.create!(:action => :create, :created_at => 10.minutes.ago) }
98
+ update = Entry.create!(:action => :update, :created_at => 5.minutes.ago) }
99
+ destroy = Entry.create!(:action => :destroy, :created_at => 1.minutes.ago) }
100
+
101
+ Entry.creates.to_a.should == [create]
102
+ Entry.updates.to_a.should == [update]
103
+ Entry.destroys.to_a.should == [destroy]
104
+ Entry.newest.to_a.should == [destroy, update, create]
105
+ end
106
+ ```
107
+
108
+ ## Contributing
109
+
110
+ 1. Fork it
111
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
112
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
113
+ 4. Push to the branch (`git push origin my-new-feature`)
114
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,60 @@
1
+ require "mongoid/audit_log/version"
2
+ require "mongoid/audit_log/actions"
3
+ require "mongoid/audit_log/entry"
4
+ require "mongoid/audit_log/changes"
5
+ require "mongoid/audit_log/embedded_changes"
6
+
7
+ module Mongoid
8
+ module AuditLog
9
+ extend ActiveSupport::Concern
10
+
11
+ mattr_accessor :modifier_class_name
12
+ self.modifier_class_name = 'User'
13
+
14
+ included do
15
+ has_many :audit_log_entries, :as => :audited,
16
+ :class_name => 'Mongoid::AuditLog::Entry'
17
+
18
+ Mongoid::AuditLog.actions.each do |action|
19
+ send("before_#{action}") do
20
+ set_audit_log_changes if Mongoid::AuditLog.recording?
21
+ end
22
+
23
+ send("after_#{action}") do
24
+ save_audit_log_entry(action) if Mongoid::AuditLog.recording?
25
+ end
26
+ end
27
+ end
28
+
29
+ def self.record(modifier = nil)
30
+ Thread.current[:mongoid_audit_log_recording] = true
31
+ Thread.current[:mongoid_audit_log_modifier] = modifier
32
+ yield
33
+ Thread.current[:mongoid_audit_log_recording] = nil
34
+ Thread.current[:mongoid_audit_log_modifier] = nil
35
+ end
36
+
37
+ def self.recording?
38
+ !!Thread.current[:mongoid_audit_log_recording]
39
+ end
40
+
41
+ def self.current_modifier
42
+ Thread.current[:mongoid_audit_log_modifier]
43
+ end
44
+
45
+ private
46
+
47
+ def set_audit_log_changes
48
+ @_audit_log_changes = Mongoid::AuditLog::Changes.new(self).tap(&:read)
49
+ end
50
+
51
+ def save_audit_log_entry(action)
52
+ Mongoid::AuditLog::Entry.create!(
53
+ :action => action,
54
+ :audited_type => self.class,
55
+ :audited_id => id,
56
+ :tracked_changes => @_audit_log_changes.all
57
+ )
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,6 @@
1
+ module Mongoid
2
+ module AuditLog
3
+ mattr_accessor :actions
4
+ self.actions = [:create, :update, :destroy]
5
+ end
6
+ end
@@ -0,0 +1,68 @@
1
+ module Mongoid
2
+ module AuditLog
3
+ class Changes
4
+ attr_reader :model
5
+ delegate :blank?, :present?, :to => :all
6
+
7
+ def self.ch_ch_ch_ch_ch_changes
8
+ puts "turn and face the strange changes"
9
+ end
10
+
11
+ def self.extract_from(value)
12
+ if value.is_a?(Hash)
13
+ raise ArgumentError, 'does not support hashes'
14
+ elsif value.is_a?(Enumerable)
15
+ changes = value.map do |model|
16
+ Mongoid::AuditLog::Changes.new(model).all
17
+ end
18
+
19
+ changes.reject(&:blank?)
20
+ else
21
+ Mongoid::AuditLog::Changes.new(value).all
22
+ end
23
+ end
24
+
25
+ def self.clean_fields(*disallowed_fields)
26
+ options = disallowed_fields.extract_options!
27
+
28
+ unless options.has_key?(:from)
29
+ raise ArgumentError, ':from is a required argument'
30
+ end
31
+
32
+ changes = options[:from]
33
+
34
+ if changes.is_a?(Hash)
35
+ changes.except(*disallowed_fields).inject({}) do |memo, t|
36
+ key, value = *t
37
+ memo.merge!(key => clean_fields(*disallowed_fields, :from => value))
38
+ end
39
+ elsif changes.is_a?(Enumerable)
40
+ changes.map { |c| clean_fields(*disallowed_fields, :from => c) }
41
+ else
42
+ changes
43
+ end
44
+ end
45
+
46
+ def initialize(model)
47
+ @model = model
48
+ end
49
+
50
+ def all
51
+ @all ||= if !model.changed?
52
+ {}
53
+ else
54
+ result = model.changes
55
+ result.merge!(embedded_changes) unless embedded_changes.empty?
56
+ Mongoid::AuditLog::Changes.clean_fields('_id', 'updated_at', :from => result)
57
+ end
58
+ end
59
+ alias_method :read, :all
60
+
61
+ private
62
+
63
+ def embedded_changes
64
+ @embedded_changes ||= Mongoid::AuditLog::EmbeddedChanges.new(model).all
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,33 @@
1
+ module Mongoid
2
+ module AuditLog
3
+ class EmbeddedChanges
4
+ attr_reader :model
5
+
6
+ def initialize(model)
7
+ @model = model
8
+ end
9
+
10
+ def relations
11
+ model.relations.inject({}) do |memo, t|
12
+ name, relation = *t
13
+ memo[name] = relation if relation.macro.in?(:embeds_one, :embeds_many)
14
+ memo
15
+ end
16
+ end
17
+
18
+ def all
19
+ @all ||= relations.inject({}) do |memo, t|
20
+ name = t.first
21
+ embedded = model.send(name)
22
+ changes = Mongoid::AuditLog::Changes.extract_from(embedded)
23
+
24
+ if embedded.present? && changes.present?
25
+ memo[name] = changes
26
+ end
27
+
28
+ memo
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,53 @@
1
+ module Mongoid
2
+ module AuditLog
3
+ class Entry
4
+ include Mongoid::Document
5
+ include Mongoid::Timestamps::Created
6
+
7
+ field :action, :type => Symbol
8
+ field :tracked_changes, :type => Hash, :default => {}
9
+ field :modifier_id, :type => String
10
+
11
+ belongs_to :audited, :polymorphic => true
12
+
13
+ index({ :audited_id => 1, :audited_type => 1 })
14
+ index({ :modifier_id => 1 })
15
+
16
+ scope :creates, where(:action => :create)
17
+ scope :updates, where(:action => :update)
18
+ scope :destroys, where(:action => :destroy)
19
+ scope :newest, order_by(:created_at.desc)
20
+
21
+ Mongoid::AuditLog.actions.each do |action_name|
22
+ define_method "#{action_name}?" do
23
+ action == action_name
24
+ end
25
+ end
26
+
27
+ def valid?(*)
28
+ result = super
29
+ self.modifier = Mongoid::AuditLog.current_modifier if result
30
+ result
31
+ end
32
+
33
+ def modifier
34
+ @modifier ||= if modifier_id.blank?
35
+ nil
36
+ else
37
+ klass = Mongoid::AuditLog.modifier_class_name.constantize
38
+ klass.find(modifier_id)
39
+ end
40
+ end
41
+
42
+ def modifier=(modifier)
43
+ self.modifier_id = if modifier.present? && modifier.respond_to?(:id)
44
+ modifier.id
45
+ else
46
+ modifier
47
+ end
48
+
49
+ @modifier = modifier
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,5 @@
1
+ module Mongoid
2
+ module AuditLog
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mongoid/audit_log/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "mongoid-audit_log"
8
+ spec.version = Mongoid::AuditLog::VERSION
9
+ spec.authors = ["Ben Crouse"]
10
+ spec.email = ["bencrouse@gmail.com"]
11
+ spec.description = %q{Stupid simple audit logging for Mongoid}
12
+ spec.summary = %q{No fancy versioning, undo, redo, etc. Just saves changes to Mongoid models in a separate collection.}
13
+ spec.homepage = "https://github.com/bencrouse/mongoid-audit-log"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.required_ruby_version = ">= 1.9.2"
22
+ spec.required_rubygems_version = ">= 1.3.6"
23
+
24
+ spec.add_runtime_dependency "mongoid", ["~> 3.1"]
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.3"
27
+ spec.add_development_dependency "rake"
28
+ end
@@ -0,0 +1,98 @@
1
+ require 'spec_helper'
2
+
3
+ module Mongoid
4
+ module AuditLog
5
+ describe Changes do
6
+ before(:all) do
7
+ class ::Product
8
+ include Mongoid::Document
9
+ include Mongoid::AuditLog
10
+ include Mongoid::Timestamps
11
+ field :name, :type => String
12
+ embeds_many :variants
13
+ end
14
+
15
+ class ::Variant
16
+ include Mongoid::Document
17
+ field :sku, :type => String
18
+ embedded_in :product
19
+ end
20
+ end
21
+
22
+ after(:all) do
23
+ Object.send(:remove_const, :Product)
24
+ Object.send(:remove_const, :Variant)
25
+ end
26
+
27
+ describe '.extract_from' do
28
+ context 'enumerable' do
29
+ it 'returns mapped changes' do
30
+ models = Array.new(3) { Product.new(name: rand) }
31
+ results = Changes.extract_from(models)
32
+
33
+ results.length.should == 3
34
+ end
35
+ end
36
+ end
37
+
38
+ describe '.clean_fields' do
39
+ it 'removes the fields from change hashes' do
40
+ changes = { "_id" => [nil, "52509662ace6ecd79a000009"], "name" => [nil, "Foo bar"] }
41
+ results = Changes.clean_fields('_id', from: changes)
42
+ results.should == { "name" => [nil, "Foo bar"] }
43
+ end
44
+ end
45
+
46
+ describe '#all' do
47
+ let(:product) do
48
+ product = Product.new(:name => 'Foo bar')
49
+ product.variants.build(sku: 'sku1')
50
+ product.variants.build(sku: 'sku2')
51
+ product
52
+ end
53
+
54
+ let(:changes) do
55
+ Changes.new(product).all
56
+ end
57
+
58
+ it 'has model changes' do
59
+ changes['name'].should == [nil, 'Foo bar']
60
+ end
61
+
62
+ it 'has embedded model changes' do
63
+ changes['variants'].should == [
64
+ { "sku" => [nil, "sku1"] },
65
+ { "sku" => [nil, "sku2"] }
66
+ ]
67
+ end
68
+
69
+ it 'is blank if only an ignored field is changed' do
70
+ product.save!
71
+ product.updated_at = 1.hour.from_now
72
+
73
+ changes.should_not be_present
74
+ end
75
+
76
+ it 'has changes if only the embedded model changes' do
77
+ product.save!
78
+ product.variants.first.sku = 'newsku'
79
+
80
+ changes.should == {
81
+ "variants"=> [{ "sku" =>[ "sku1", "newsku"] }]
82
+ }
83
+ end
84
+ end
85
+
86
+ describe '#present?' do
87
+ it 'is false if no embedded models have changed' do
88
+ product = Product.new(:name => 'Foo bar')
89
+ product.variants.build(sku: 'sku1')
90
+ product.variants.build(sku: 'sku2')
91
+ product.save!
92
+
93
+ Changes.new(product).should_not be_present
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ module Mongoid
4
+ module AuditLog
5
+ describe Entry do
6
+ before(:all) do
7
+ @remember_modifier_class_name = AuditLog.modifier_class_name
8
+ AuditLog.modifier_class_name = 'User'
9
+
10
+ class ::Product
11
+ include Mongoid::Document
12
+ include Mongoid::AuditLog
13
+ end
14
+ end
15
+
16
+ after(:all) do
17
+ AuditLog.modifier_class_name = @remember_modifier_class_name
18
+ Object.send(:remove_const, :Product)
19
+ end
20
+
21
+ let(:user) { User.create! }
22
+
23
+ describe 'scopes' do
24
+ let!(:create) { Entry.create!(:action => :create, :created_at => 10.minutes.ago) }
25
+ let!(:update) { Entry.create!(:action => :update, :created_at => 5.minutes.ago) }
26
+ let!(:destroy) { Entry.create!(:action => :destroy, :created_at => 1.minutes.ago) }
27
+
28
+ describe '.creates' do
29
+ it 'returns actions which are creates' do
30
+ Entry.creates.to_a.should == [create]
31
+ end
32
+ end
33
+
34
+ describe '.updates' do
35
+ it 'returns actions which are updates' do
36
+ Entry.updates.to_a.should == [update]
37
+ end
38
+ end
39
+
40
+ describe '.destroys' do
41
+ it 'returns actions which are destroys' do
42
+ Entry.destroys.to_a.should == [destroy]
43
+ end
44
+ end
45
+
46
+ describe '.newest' do
47
+ it 'sorts with newest first' do
48
+ Entry.newest.to_a.should == [destroy, update, create]
49
+ end
50
+ end
51
+ end
52
+
53
+ describe '#modifier' do
54
+ it 'finds the modifier based on the configured class' do
55
+ entry = Entry.new(:modifier_id => user.id)
56
+ entry.modifier.should == user
57
+ end
58
+ end
59
+
60
+ describe '#modifier_id=' do
61
+ let(:entry) { Entry.new }
62
+
63
+ it "sets the modifier's id" do
64
+ entry.modifier = user
65
+ entry.modifier_id.should == user.id.to_s
66
+ end
67
+
68
+ it 'sets the modifier if no id' do
69
+ entry.modifier = 'test'
70
+ entry.modifier_id.should == 'test'
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,136 @@
1
+ require 'spec_helper'
2
+
3
+ module Mongoid
4
+ describe AuditLog do
5
+ before(:all) do
6
+ class ::Product
7
+ include Mongoid::Document
8
+ include Mongoid::AuditLog
9
+ field :name, :type => String
10
+ embeds_many :variants
11
+ end
12
+
13
+ class ::Variant
14
+ include Mongoid::Document
15
+ field :sku, :type => String
16
+ embedded_in :product
17
+ end
18
+ end
19
+
20
+ after(:all) do
21
+ Object.send(:remove_const, :Product)
22
+ Object.send(:remove_const, :Variant)
23
+ end
24
+
25
+ describe '.record' do
26
+ it 'does not save an entry if not recording' do
27
+ product = Product.create!
28
+ product.audit_log_entries.should be_empty
29
+ end
30
+
31
+ it 'saves create entries' do
32
+ AuditLog.record do
33
+ product = Product.create!
34
+ product.audit_log_entries.count.should == 1
35
+ end
36
+ end
37
+
38
+ it 'saves update entries' do
39
+ AuditLog.record do
40
+ product = Product.create!(:name => 'Foo bar')
41
+ 2.times { |i| product.update_attributes(:name => "Test #{i}") }
42
+ product.audit_log_entries.count.should == 3
43
+ end
44
+ end
45
+
46
+ it 'saves destroy entries' do
47
+ AuditLog.record do
48
+ product = Product.create!
49
+ product.destroy
50
+ AuditLog::Entry.count.should == 2
51
+ end
52
+ end
53
+
54
+ it 'saves the modifier if passed' do
55
+ user = User.create!
56
+ AuditLog.record(user) do
57
+ product = Product.create!
58
+ product.audit_log_entries.first.modifier.should == user
59
+ end
60
+ end
61
+ end
62
+
63
+ describe 'callbacks' do
64
+ let(:user) { User.create! }
65
+
66
+ around(:each) do |example|
67
+ AuditLog.record(user) do
68
+ example.run
69
+ end
70
+ end
71
+
72
+ context 'create' do
73
+ it 'saves details' do
74
+ product = Product.create!(:name => 'Foo bar')
75
+ entry = product.audit_log_entries.first
76
+
77
+ entry.create?.should be_true
78
+ entry.tracked_changes.should == { 'name' => [nil, 'Foo bar'] }
79
+ end
80
+
81
+ it 'saves embedded creations' do
82
+ product = Product.new(:name => 'Foo bar')
83
+ product.variants.build(sku: 'sku')
84
+ product.save!
85
+
86
+ entry = product.audit_log_entries.first
87
+
88
+ entry.create?.should be_true
89
+ entry.tracked_changes.should == {
90
+ 'name' => [nil, 'Foo bar'],
91
+ 'variants' => [{ 'sku' => [nil, 'sku'] }]
92
+ }
93
+ end
94
+ end
95
+
96
+ context 'update' do
97
+ it 'saves details' do
98
+ product = Product.create!(:name => 'Foo bar')
99
+ product.update_attributes(:name => 'Bar baz')
100
+ entry = product.audit_log_entries.last
101
+
102
+ entry.update?.should be_true
103
+ entry.tracked_changes.should == { 'name' => ['Foo bar', 'Bar baz'] }
104
+ end
105
+
106
+ it 'saves embedded updates' do
107
+ product = Product.new(:name => 'Foo bar')
108
+ product.variants.build(sku: 'sku')
109
+ product.save!
110
+
111
+ product.name = 'Bar baz'
112
+ product.variants.first.sku = 'newsku'
113
+ product.save!
114
+
115
+ entry = product.audit_log_entries.last
116
+
117
+ entry.update?.should be_true
118
+ entry.tracked_changes.should == {
119
+ 'name' => ['Foo bar', 'Bar baz'],
120
+ 'variants' => [{ 'sku' => ['sku', 'newsku'] }]
121
+ }
122
+ end
123
+ end
124
+
125
+ context 'destroy' do
126
+ it 'saves an entry' do
127
+ product = Product.create!(:name => 'Foo bar')
128
+ product.destroy
129
+ entry = product.audit_log_entries.last
130
+
131
+ entry.destroy?.should be_true
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'mongoid'
4
+ require 'mongoid/audit_log'
5
+ require 'rspec'
6
+
7
+ Mongoid.configure do |config|
8
+ config.connect_to('mongoid_audit_log_test')
9
+ end
10
+
11
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
12
+
13
+ RSpec.configure do |config|
14
+ config.mock_with :rspec
15
+ config.after(:each) { Mongoid.purge! }
16
+ end
@@ -0,0 +1,3 @@
1
+ class User
2
+ include Mongoid::Document
3
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mongoid-audit_log
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ben Crouse
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mongoid
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '3.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '3.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Stupid simple audit logging for Mongoid
56
+ email:
57
+ - bencrouse@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - .rspec
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - lib/mongoid/audit_log.rb
69
+ - lib/mongoid/audit_log/actions.rb
70
+ - lib/mongoid/audit_log/changes.rb
71
+ - lib/mongoid/audit_log/embedded_changes.rb
72
+ - lib/mongoid/audit_log/entry.rb
73
+ - lib/mongoid/audit_log/version.rb
74
+ - mongoid-audit_log.gemspec
75
+ - spec/mongoid/audit_log/changes_spec.rb
76
+ - spec/mongoid/audit_log/entry_spec.rb
77
+ - spec/mongoid/audit_log_spec.rb
78
+ - spec/spec_helper.rb
79
+ - spec/support/models.rb
80
+ homepage: https://github.com/bencrouse/mongoid-audit-log
81
+ licenses:
82
+ - MIT
83
+ metadata: {}
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: 1.9.2
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ! '>='
96
+ - !ruby/object:Gem::Version
97
+ version: 1.3.6
98
+ requirements: []
99
+ rubyforge_project:
100
+ rubygems_version: 2.0.3
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: No fancy versioning, undo, redo, etc. Just saves changes to Mongoid models
104
+ in a separate collection.
105
+ test_files:
106
+ - spec/mongoid/audit_log/changes_spec.rb
107
+ - spec/mongoid/audit_log/entry_spec.rb
108
+ - spec/mongoid/audit_log_spec.rb
109
+ - spec/spec_helper.rb
110
+ - spec/support/models.rb
111
+ has_rdoc: