audited 4.2.2 → 4.3.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of audited might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +10 -9
- data/Appraisals +10 -6
- data/Gemfile +1 -13
- data/README.md +46 -33
- data/Rakefile +3 -18
- data/gemfiles/rails40.gemfile +1 -5
- data/gemfiles/rails41.gemfile +1 -5
- data/gemfiles/rails42.gemfile +1 -5
- data/gemfiles/rails50.gemfile +8 -0
- data/lib/audited-rspec.rb +4 -0
- data/lib/audited.rb +15 -2
- data/lib/audited/audit.rb +97 -57
- data/lib/audited/auditor.rb +73 -45
- data/lib/audited/rspec_matchers.rb +6 -2
- data/lib/audited/sweeper.rb +12 -23
- data/lib/audited/version.rb +1 -1
- data/lib/generators/audited/install_generator.rb +20 -0
- data/lib/generators/audited/migration.rb +15 -0
- data/lib/generators/audited/templates/add_association_to_audits.rb +11 -0
- data/lib/generators/audited/templates/add_comment_to_audits.rb +9 -0
- data/lib/generators/audited/templates/add_remote_address_to_audits.rb +10 -0
- data/lib/generators/audited/templates/add_request_uuid_to_audits.rb +10 -0
- data/lib/generators/audited/templates/install.rb +30 -0
- data/lib/generators/audited/templates/rename_association_to_associated.rb +23 -0
- data/lib/generators/audited/templates/rename_changes_to_audited_changes.rb +9 -0
- data/lib/generators/audited/templates/rename_parent_to_association.rb +11 -0
- data/lib/generators/audited/upgrade_generator.rb +57 -0
- data/spec/audited/audit_spec.rb +199 -0
- data/spec/audited/auditor_spec.rb +607 -0
- data/spec/audited/sweeper_spec.rb +106 -0
- data/spec/audited_spec_helpers.rb +6 -22
- data/spec/rails_app/config/environments/test.rb +7 -4
- data/spec/rails_app/config/initializers/secret_token.rb +1 -1
- data/spec/rails_app/config/routes.rb +1 -4
- data/spec/spec_helper.rb +7 -9
- data/spec/support/active_record/models.rb +20 -13
- data/spec/support/active_record/schema.rb +36 -12
- data/test/db/version_1.rb +4 -4
- data/test/db/version_2.rb +4 -4
- data/test/db/version_3.rb +4 -4
- data/test/db/version_4.rb +4 -4
- data/test/db/version_5.rb +2 -2
- data/test/db/version_6.rb +2 -2
- data/test/install_generator_test.rb +1 -1
- data/test/upgrade_generator_test.rb +10 -10
- metadata +73 -37
- data/lib/audited/active_record/version.rb +0 -5
- data/lib/audited/mongo_mapper/version.rb +0 -5
- data/spec/support/mongo_mapper/connection.rb +0 -4
- data/spec/support/mongo_mapper/models.rb +0 -214
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b04e8c93cc4b6351654924948b663708433e8a01
|
4
|
+
data.tar.gz: ce147cca64fde0e62e06bd7235851a907ec4ccb5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f9fc970bef11b25088cc77123857efad07fb319b84a82696e6f195cce0b9cb1c90cac1a3b0330e57143a61b8a38d9973b13a9618421adeebae030f8f483a9f42
|
7
|
+
data.tar.gz: a7841493a1889185d35c323287d98fd9ca332a91fa18f5d751fcff77508baafb5a2e1a5056eeeb1d6e5fd8efe3d9f13aa407403c85038303642dbd631c7817f9
|
data/.travis.yml
CHANGED
@@ -1,28 +1,29 @@
|
|
1
1
|
language: ruby
|
2
|
-
|
2
|
+
cache: bundler
|
3
3
|
rvm:
|
4
|
-
- 2.0
|
5
4
|
- 2.1
|
6
|
-
- 2.2
|
7
|
-
-
|
5
|
+
- 2.2.4
|
6
|
+
- 2.3.1
|
7
|
+
- ruby-head
|
8
8
|
env:
|
9
9
|
- DB=SQLITE
|
10
10
|
- DB=POSTGRES
|
11
11
|
- DB=MYSQL
|
12
|
-
before_script:
|
13
|
-
- mysql -e 'create database audited_test;'
|
14
|
-
- psql -c 'create database audited_test;' -U postgres
|
15
12
|
gemfile:
|
16
13
|
- gemfiles/rails40.gemfile
|
17
14
|
- gemfiles/rails41.gemfile
|
18
15
|
- gemfiles/rails42.gemfile
|
16
|
+
- gemfiles/rails50.gemfile
|
19
17
|
matrix:
|
20
18
|
allow_failures:
|
21
|
-
- rvm:
|
19
|
+
- rvm: ruby-head
|
20
|
+
exclude:
|
21
|
+
- rvm: 2.1
|
22
|
+
gemfile: gemfiles/rails50.gemfile
|
23
|
+
fast_finish: true
|
22
24
|
branches:
|
23
25
|
only:
|
24
26
|
- master
|
25
|
-
- 4.2-stable
|
26
27
|
sudo: false
|
27
28
|
notifications:
|
28
29
|
webhooks:
|
data/Appraisals
CHANGED
@@ -1,18 +1,22 @@
|
|
1
1
|
appraise 'rails40' do
|
2
2
|
gem 'rails', '~> 4.0.0'
|
3
|
-
gem '
|
3
|
+
gem 'protected_attributes'
|
4
4
|
gem 'test-unit'
|
5
|
-
gem 'mysql2', '~> 0.3.0'
|
6
5
|
end
|
7
6
|
|
8
7
|
appraise 'rails41' do
|
9
8
|
gem 'rails', '~> 4.1.0'
|
10
|
-
gem '
|
11
|
-
gem 'mysql2', '~> 0.3.0'
|
9
|
+
gem 'protected_attributes'
|
12
10
|
end
|
13
11
|
|
14
12
|
appraise 'rails42' do
|
15
13
|
gem 'rails', '~> 4.2.0'
|
16
|
-
gem '
|
17
|
-
|
14
|
+
gem 'protected_attributes'
|
15
|
+
end
|
16
|
+
|
17
|
+
appraise 'rails50' do
|
18
|
+
gem 'rails', '~> 5.0.0'
|
19
|
+
|
20
|
+
# The following needs to point to Github until the release of 0.1.3
|
21
|
+
gem 'rails-observers', github: 'rails/rails-observers', branch: 'master'
|
18
22
|
end
|
data/Gemfile
CHANGED
@@ -1,15 +1,3 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
|
-
gemspec :
|
4
|
-
# JRuby support for the test ENV
|
5
|
-
unless defined?(JRUBY_VERSION)
|
6
|
-
gem 'sqlite3', '~> 1.2'
|
7
|
-
gem 'mysql2', '~> 0.3'
|
8
|
-
gem 'pg', '~> 0.17'
|
9
|
-
gem 'bson_ext', '~> 1.6'
|
10
|
-
else
|
11
|
-
gem 'activerecord-jdbcsqlite3-adapter', '~> 1.3'
|
12
|
-
gem 'activerecord-jdbcpostgresql-adapter', '~> 1.3'
|
13
|
-
gem 'activerecord-jdbcmysql-adapter', '~> 1.3'
|
14
|
-
gem 'bson', '~> 1.6'
|
15
|
-
end
|
3
|
+
gemspec name: "audited"
|
data/README.md
CHANGED
@@ -1,37 +1,37 @@
|
|
1
|
-
Audited [![Build Status](https://secure.travis-ci.org/collectiveidea/audited.
|
1
|
+
Audited [![Build Status](https://secure.travis-ci.org/collectiveidea/audited.svg)](http://travis-ci.org/collectiveidea/audited) [![Dependency Status](https://gemnasium.com/collectiveidea/audited.svg)](https://gemnasium.com/collectiveidea/audited)[![Code Climate](https://codeclimate.com/github/collectiveidea/audited.svg)](https://codeclimate.com/github/collectiveidea/audited) [![Security](https://hakiri.io/github/collectiveidea/audited/master.svg)](https://hakiri.io/github/collectiveidea/audited/master)
|
2
2
|
=======
|
3
3
|
|
4
|
-
**Audited** (previously acts_as_audited) is an ORM extension that logs all changes to your models. Audited also
|
4
|
+
**Audited** (previously acts_as_audited) is an ORM extension that logs all changes to your models. Audited can also record who made those changes, save comments and associate models related to the changes.
|
5
5
|
|
6
|
-
Audited currently (4.x) works with Rails 4.2.
|
6
|
+
Audited currently (4.x) works with Rails 5.0 and 4.2. It may work with 4.1 and 4.0, but this is not guaranteed.
|
7
|
+
|
8
|
+
For Rails 3, use gem version 3.0 or see the [3.0-stable branch](https://github.com/collectiveidea/audited/tree/3.0-stable).
|
7
9
|
|
8
10
|
## Supported Rubies
|
9
11
|
|
10
12
|
Audited supports and is [tested against](http://travis-ci.org/collectiveidea/audited) the following Ruby versions:
|
11
13
|
|
12
|
-
* 2.0.0
|
13
14
|
* 2.1.5
|
14
|
-
* 2.2.
|
15
|
+
* 2.2.4
|
16
|
+
* 2.3.1
|
15
17
|
|
16
18
|
Audited may work just fine with a Ruby version not listed above, but we can't guarantee that it will. If you'd like to maintain a Ruby that isn't listed, please let us know with a [pull request](https://github.com/collectiveidea/audited/pulls).
|
17
19
|
|
18
20
|
## Supported ORMs
|
19
21
|
|
20
|
-
In a previous life, Audited
|
21
|
-
|
22
|
-
* ActiveRecord
|
23
|
-
* MongoMapper
|
22
|
+
Audited is currently ActiveRecord-only. In a previous life, Audited worked with MongoMapper. Use the [4.2-stable branch](https://github.com/collectiveidea/audited/tree/4.2-stable) if you need MongoMapper.
|
24
23
|
|
25
24
|
## Installation
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
### ActiveRecord
|
26
|
+
Add the gem to your Gemfile:
|
30
27
|
|
31
|
-
|
28
|
+
```ruby
|
29
|
+
gem "audited", "~> 4.3"
|
30
|
+
```
|
32
31
|
|
32
|
+
If you are using rails 5.0, you would also need the following line in your Gemfile.
|
33
33
|
```ruby
|
34
|
-
gem "
|
34
|
+
gem "rails-observers", github: 'rails/rails-observers'
|
35
35
|
```
|
36
36
|
|
37
37
|
Then, from your Rails app directory, create the `audits` table:
|
@@ -52,11 +52,6 @@ $ rake db:migrate
|
|
52
52
|
|
53
53
|
Upgrading will only make changes if changes are needed.
|
54
54
|
|
55
|
-
### MongoMapper
|
56
|
-
|
57
|
-
```ruby
|
58
|
-
gem "audited-mongo_mapper", "~> 4.0"
|
59
|
-
```
|
60
55
|
|
61
56
|
## Usage
|
62
57
|
|
@@ -88,6 +83,15 @@ audit.action # => "update"
|
|
88
83
|
audit.audited_changes # => {"name"=>["Steve", "Ryan"]}
|
89
84
|
```
|
90
85
|
|
86
|
+
You can get previous versions of a record by index or date, or list all
|
87
|
+
revisions.
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
user.revisions
|
91
|
+
user.revision(1)
|
92
|
+
user.revision_at(Date.parse("2016-01-01"))
|
93
|
+
```
|
94
|
+
|
91
95
|
### Specifying columns
|
92
96
|
|
93
97
|
By default, a new audit is created for any attribute changes. You can, however, limit the columns to be considered.
|
@@ -143,7 +147,7 @@ end
|
|
143
147
|
|
144
148
|
If you're using Audited in a Rails application, all audited changes made within a request will automatically be attributed to the current user. By default, Audited uses the `current_user` method in your controller.
|
145
149
|
|
146
|
-
```
|
150
|
+
```ruby
|
147
151
|
class PostsController < ApplicationController
|
148
152
|
def create
|
149
153
|
current_user # => #<User name: "Steve">
|
@@ -162,12 +166,28 @@ Audited.current_user_method = :authenticated_user
|
|
162
166
|
Outside of a request, Audited can still record the user with the `as_user` method:
|
163
167
|
|
164
168
|
```ruby
|
165
|
-
Audited.
|
169
|
+
Audited::Audit.as_user(User.find(1)) do
|
166
170
|
post.update_attribute!(title: "Hello, world!")
|
167
171
|
end
|
168
172
|
post.audits.last.user # => #<User id: 1>
|
169
173
|
```
|
170
174
|
|
175
|
+
#### Custom Auditor
|
176
|
+
|
177
|
+
You might need to use a custom auditor from time to time. It can be done by simply passing in a string:
|
178
|
+
|
179
|
+
```ruby
|
180
|
+
class ApplicationController < ActionController::Base
|
181
|
+
def authenticated_user
|
182
|
+
if current_user
|
183
|
+
current_user
|
184
|
+
else
|
185
|
+
'Elon Musk'
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
```
|
190
|
+
|
171
191
|
### Associated Audits
|
172
192
|
|
173
193
|
Sometimes it's useful to associate an audit with a model other than the one being changed. For instance, given the following models:
|
@@ -240,15 +260,12 @@ User.auditing_enabled = false
|
|
240
260
|
|
241
261
|
## Gotchas
|
242
262
|
|
243
|
-
### Using attr_protected
|
263
|
+
### Using attr_protected with Rails 4.x
|
244
264
|
|
245
|
-
|
246
|
-
`attr_protected` or `strong_parameters`, you'll have to take an extra step or
|
247
|
-
two.
|
265
|
+
If you're using the `protected_attributes` gem with Rails 4.0, 4.1 or 4.2 (the gem isn't supported in Rails 5.0 or higher), you'll have to take an extra couple of steps to get `audited` working.
|
248
266
|
|
249
|
-
|
250
|
-
|
251
|
-
interfere with `strong_parameters` and none of your `save` calls will work.
|
267
|
+
First be sure to add `allow_mass_assignment: true` to your `audited` call; otherwise Audited will
|
268
|
+
interfere with `protected_attributes` and none of your `save` calls will work.
|
252
269
|
|
253
270
|
```ruby
|
254
271
|
class User < ActiveRecord::Base
|
@@ -256,7 +273,7 @@ class User < ActiveRecord::Base
|
|
256
273
|
end
|
257
274
|
```
|
258
275
|
|
259
|
-
|
276
|
+
Second, be sure to add `audit_ids` to the list of protected attributes to prevent data loss.
|
260
277
|
|
261
278
|
```ruby
|
262
279
|
class User < ActiveRecord::Base
|
@@ -265,10 +282,6 @@ class User < ActiveRecord::Base
|
|
265
282
|
end
|
266
283
|
```
|
267
284
|
|
268
|
-
### MongoMapper Embedded Documents
|
269
|
-
|
270
|
-
Currently, Audited does not track changes on embedded documents. Audited works by tracking a model's [dirty changes](http://api.rubyonrails.org/classes/ActiveModel/Dirty.html) but changes to embedded documents don't appear in dirty tracking.
|
271
|
-
|
272
285
|
## Support
|
273
286
|
|
274
287
|
You can find documentation at: http://rdoc.info/github/collectiveidea/audited
|
data/Rakefile
CHANGED
@@ -5,24 +5,9 @@ require 'rspec/core/rake_task'
|
|
5
5
|
require 'rake/testtask'
|
6
6
|
require 'appraisal'
|
7
7
|
|
8
|
-
Bundler::GemHelper.install_tasks(:
|
9
|
-
Bundler::GemHelper.install_tasks(:name => 'audited-activerecord')
|
10
|
-
Bundler::GemHelper.install_tasks(:name => 'audited-mongo_mapper')
|
8
|
+
Bundler::GemHelper.install_tasks(name: 'audited')
|
11
9
|
|
12
|
-
|
13
|
-
|
14
|
-
ADAPTERS.each do |adapter|
|
15
|
-
desc "Run RSpec code examples for #{adapter} adapter"
|
16
|
-
RSpec::Core::RakeTask.new(adapter) do |t|
|
17
|
-
t.pattern = "spec/audited/adapters/#{adapter}/**/*_spec.rb"
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
task :spec do
|
22
|
-
ADAPTERS.each do |adapter|
|
23
|
-
Rake::Task[adapter].invoke
|
24
|
-
end
|
25
|
-
end
|
10
|
+
RSpec::Core::RakeTask.new(:spec)
|
26
11
|
|
27
12
|
Rake::TestTask.new do |t|
|
28
13
|
t.libs << "test"
|
@@ -30,4 +15,4 @@ Rake::TestTask.new do |t|
|
|
30
15
|
t.verbose = true
|
31
16
|
end
|
32
17
|
|
33
|
-
task :
|
18
|
+
task default: [:spec, :test]
|
data/gemfiles/rails40.gemfile
CHANGED
@@ -2,12 +2,8 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "sqlite3", "~> 1.2"
|
6
|
-
gem "mysql2", "~> 0.3.0"
|
7
|
-
gem "pg", "~> 0.17"
|
8
|
-
gem "bson_ext", "~> 1.6"
|
9
5
|
gem "rails", "~> 4.0.0"
|
10
|
-
gem "
|
6
|
+
gem "protected_attributes"
|
11
7
|
gem "test-unit"
|
12
8
|
|
13
9
|
gemspec :name => "audited", :path => "../"
|
data/gemfiles/rails41.gemfile
CHANGED
@@ -2,11 +2,7 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "sqlite3", "~> 1.2"
|
6
|
-
gem "mysql2", "~> 0.3.0"
|
7
|
-
gem "pg", "~> 0.17"
|
8
|
-
gem "bson_ext", "~> 1.6"
|
9
5
|
gem "rails", "~> 4.1.0"
|
10
|
-
gem "
|
6
|
+
gem "protected_attributes"
|
11
7
|
|
12
8
|
gemspec :name => "audited", :path => "../"
|
data/gemfiles/rails42.gemfile
CHANGED
@@ -2,11 +2,7 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "sqlite3", "~> 1.2"
|
6
|
-
gem "mysql2", "~> 0.4.0"
|
7
|
-
gem "pg", "~> 0.17"
|
8
|
-
gem "bson_ext", "~> 1.6"
|
9
5
|
gem "rails", "~> 4.2.0"
|
10
|
-
gem "
|
6
|
+
gem "protected_attributes"
|
11
7
|
|
12
8
|
gemspec :name => "audited", :path => "../"
|
data/lib/audited.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
require 'rails/observers/active_model/active_model'
|
2
|
-
|
2
|
+
require 'active_record'
|
3
3
|
|
4
4
|
module Audited
|
5
5
|
class << self
|
6
|
-
attr_accessor :ignored_attributes, :current_user_method
|
6
|
+
attr_accessor :ignored_attributes, :current_user_method
|
7
|
+
|
8
|
+
# Deprecate audit_class accessors in preperation of their removal
|
9
|
+
def audit_class
|
10
|
+
Audited::Audit
|
11
|
+
end
|
12
|
+
deprecate audit_class: "Audited.audit_class is now always Audited::Audit. This method will be removed."
|
7
13
|
|
8
14
|
def store
|
9
15
|
Thread.current[:audited_store] ||= {}
|
@@ -14,3 +20,10 @@ module Audited
|
|
14
20
|
|
15
21
|
@current_user_method = :current_user
|
16
22
|
end
|
23
|
+
|
24
|
+
require 'audited/auditor'
|
25
|
+
require 'audited/audit'
|
26
|
+
|
27
|
+
::ActiveRecord::Base.send :include, Audited::Auditor
|
28
|
+
|
29
|
+
require 'audited/sweeper'
|
data/lib/audited/audit.rb
CHANGED
@@ -1,60 +1,44 @@
|
|
1
|
-
|
2
|
-
module Audit
|
3
|
-
def self.included(klass)
|
4
|
-
klass.extend(ClassMethods)
|
5
|
-
klass.setup_audit
|
6
|
-
end
|
1
|
+
require 'set'
|
7
2
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
3
|
+
module Audited
|
4
|
+
# Audit saves the changes to ActiveRecord models. It has the following attributes:
|
5
|
+
#
|
6
|
+
# * <tt>auditable</tt>: the ActiveRecord model that was changed
|
7
|
+
# * <tt>user</tt>: the user that performed the change; a string or an ActiveRecord model
|
8
|
+
# * <tt>action</tt>: one of create, update, or delete
|
9
|
+
# * <tt>audited_changes</tt>: a serialized hash of all the changes
|
10
|
+
# * <tt>comment</tt>: a comment set with the audit
|
11
|
+
# * <tt>version</tt>: the version of the model
|
12
|
+
# * <tt>request_uuid</tt>: a uuid based that allows audits from the same controller request
|
13
|
+
# * <tt>created_at</tt>: Time that the change was performed
|
14
|
+
#
|
15
|
+
class Audit < ::ActiveRecord::Base
|
16
|
+
include ActiveModel::Observing
|
13
17
|
|
14
|
-
|
18
|
+
belongs_to :auditable, polymorphic: true
|
19
|
+
belongs_to :user, polymorphic: true
|
20
|
+
belongs_to :associated, polymorphic: true
|
15
21
|
|
16
|
-
|
17
|
-
self.audited_class_names = Set.new
|
18
|
-
end
|
22
|
+
before_create :set_version_number, :set_audit_user, :set_request_uuid
|
19
23
|
|
20
|
-
|
21
|
-
|
22
|
-
audited_class_names.map(&:constantize)
|
23
|
-
end
|
24
|
-
|
25
|
-
# All audits made during the block called will be recorded as made
|
26
|
-
# by +user+. This method is hopefully threadsafe, making it ideal
|
27
|
-
# for background operations that require audit information.
|
28
|
-
def as_user(user, &block)
|
29
|
-
Thread.current[:audited_user] = user
|
30
|
-
yield
|
31
|
-
ensure
|
32
|
-
Thread.current[:audited_user] = nil
|
33
|
-
end
|
24
|
+
cattr_accessor :audited_class_names
|
25
|
+
self.audited_class_names = Set.new
|
34
26
|
|
35
|
-
|
36
|
-
def reconstruct_attributes(audits)
|
37
|
-
attributes = {}
|
38
|
-
result = audits.collect do |audit|
|
39
|
-
attributes.merge!(audit.new_attributes).merge!(:version => audit.version)
|
40
|
-
yield attributes if block_given?
|
41
|
-
end
|
42
|
-
block_given? ? result : attributes
|
43
|
-
end
|
27
|
+
serialize :audited_changes
|
44
28
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
29
|
+
scope :ascending, ->{ reorder(version: :asc) }
|
30
|
+
scope :descending, ->{ reorder(version: :desc)}
|
31
|
+
scope :creates, ->{ where(action: 'create')}
|
32
|
+
scope :updates, ->{ where(action: 'update')}
|
33
|
+
scope :destroys, ->{ where(action: 'destroy')}
|
49
34
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
35
|
+
scope :up_until, ->(date_or_time){ where("created_at <= ?", date_or_time) }
|
36
|
+
scope :from_version, ->(version){ where('version >= ?', version) }
|
37
|
+
scope :to_version, ->(version){ where('version <= ?', version) }
|
38
|
+
scope :auditable_finder, ->(auditable_id, auditable_type){ where(auditable_id: auditable_id, auditable_type: auditable_type)}
|
39
|
+
# Return all audits older than the current one.
|
40
|
+
def ancestors
|
41
|
+
self.class.ascending.auditable_finder(auditable_id, auditable_type).to_version(version)
|
58
42
|
end
|
59
43
|
|
60
44
|
# Return an instance of what the object looked like at this revision. If
|
@@ -62,13 +46,13 @@ module Audited
|
|
62
46
|
def revision
|
63
47
|
clazz = auditable_type.constantize
|
64
48
|
(clazz.find_by_id(auditable_id) || clazz.new).tap do |m|
|
65
|
-
self.class.assign_revision_attributes(m, self.class.reconstruct_attributes(ancestors).merge(
|
49
|
+
self.class.assign_revision_attributes(m, self.class.reconstruct_attributes(ancestors).merge(version: version))
|
66
50
|
end
|
67
51
|
end
|
68
52
|
|
69
53
|
# Returns a hash of the changed attributes with the new values
|
70
54
|
def new_attributes
|
71
|
-
(audited_changes || {}).inject({}.with_indifferent_access) do |attrs,(attr,values)|
|
55
|
+
(audited_changes || {}).inject({}.with_indifferent_access) do |attrs, (attr, values)|
|
72
56
|
attrs[attr] = values.is_a?(Array) ? values.last : values
|
73
57
|
attrs
|
74
58
|
end
|
@@ -76,19 +60,75 @@ module Audited
|
|
76
60
|
|
77
61
|
# Returns a hash of the changed attributes with the old values
|
78
62
|
def old_attributes
|
79
|
-
(audited_changes || {}).inject({}.with_indifferent_access) do |attrs,(attr,values)|
|
63
|
+
(audited_changes || {}).inject({}.with_indifferent_access) do |attrs, (attr, values)|
|
80
64
|
attrs[attr] = Array(values).first
|
81
65
|
|
82
66
|
attrs
|
83
67
|
end
|
84
68
|
end
|
85
69
|
|
70
|
+
# Allows user to be set to either a string or an ActiveRecord object
|
71
|
+
# @private
|
72
|
+
def user_as_string=(user)
|
73
|
+
# reset both either way
|
74
|
+
self.user_as_model = self.username = nil
|
75
|
+
user.is_a?(::ActiveRecord::Base) ?
|
76
|
+
self.user_as_model = user :
|
77
|
+
self.username = user
|
78
|
+
end
|
79
|
+
alias_method :user_as_model=, :user=
|
80
|
+
alias_method :user=, :user_as_string=
|
81
|
+
|
82
|
+
# @private
|
83
|
+
def user_as_string
|
84
|
+
user_as_model || username
|
85
|
+
end
|
86
|
+
alias_method :user_as_model, :user
|
87
|
+
alias_method :user, :user_as_string
|
88
|
+
|
89
|
+
# Returns the list of classes that are being audited
|
90
|
+
def self.audited_classes
|
91
|
+
audited_class_names.map(&:constantize)
|
92
|
+
end
|
93
|
+
|
94
|
+
# All audits made during the block called will be recorded as made
|
95
|
+
# by +user+. This method is hopefully threadsafe, making it ideal
|
96
|
+
# for background operations that require audit information.
|
97
|
+
def self.as_user(user, &block)
|
98
|
+
Thread.current[:audited_user] = user
|
99
|
+
yield
|
100
|
+
ensure
|
101
|
+
Thread.current[:audited_user] = nil
|
102
|
+
end
|
103
|
+
|
104
|
+
# @private
|
105
|
+
def self.reconstruct_attributes(audits)
|
106
|
+
attributes = {}
|
107
|
+
result = audits.collect do |audit|
|
108
|
+
attributes.merge!(audit.new_attributes)[:version] = audit.version
|
109
|
+
yield attributes if block_given?
|
110
|
+
end
|
111
|
+
block_given? ? result : attributes
|
112
|
+
end
|
113
|
+
|
114
|
+
# @private
|
115
|
+
def self.assign_revision_attributes(record, attributes)
|
116
|
+
attributes.each do |attr, val|
|
117
|
+
record = record.dup if record.frozen?
|
118
|
+
|
119
|
+
if record.respond_to?("#{attr}=")
|
120
|
+
record.attributes.key?(attr.to_s) ?
|
121
|
+
record[attr] = val :
|
122
|
+
record.send("#{attr}=", val)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
record
|
126
|
+
end
|
127
|
+
|
86
128
|
private
|
129
|
+
|
87
130
|
def set_version_number
|
88
|
-
max = self.class.
|
89
|
-
:auditable_id => auditable_id,
|
90
|
-
:auditable_type => auditable_type
|
91
|
-
).order(:version.desc).first.try(:version) || 0
|
131
|
+
max = self.class.auditable_finder(auditable_id, auditable_type).descending.first.try(:version) || 0
|
92
132
|
self.version = max + 1
|
93
133
|
end
|
94
134
|
|