rails_log_book 0.3.0 → 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 +5 -5
- data/README.md +168 -12
- data/lib/generators/log_book/install_generator.rb +7 -1
- data/lib/generators/log_book/templates/install.rb +2 -2
- data/lib/log_book/controller_record.rb +1 -1
- data/lib/log_book/recorder.rb +16 -17
- data/lib/log_book/squash_records.rb +18 -7
- data/lib/log_book/version.rb +1 -1
- data/log_book.gemspec +2 -2
- metadata +8 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 33c84201892d61f332f7f60bd66ac9d052c37b9d9a894e5210eecf528efcb1ee
|
4
|
+
data.tar.gz: 2dd8618869a1a1955e8c24261edbd11561662792d39e736de94513ea32b28358
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1f0b026c941e50454283953976c11eef81cba06e8c37ddb6ffaffbfb1ca1c3ef030c1b6e82c5be68c9151948465fa335ae4f3b79a8e2606a4a0190559e6f07cd
|
7
|
+
data.tar.gz: 0b321da7a85b6fe8620fe1863ac26560c3dd40a5fa06eabf1a7d4d1ec0f299d296994634370bac9c66a82990440ae2d578ced623b617474d2f864ec8b6443bde
|
data/README.md
CHANGED
@@ -1,29 +1,185 @@
|
|
1
1
|
# LogBook
|
2
2
|
|
3
|
-
|
3
|
+
LogBook is a gem that tracks changes on your records. Created for the purpuse of auditing and showing activity log.
|
4
|
+
For comparison with [paper_\__trail](https://github.com/airblade/paper_trail) and [audited](https://github.com/collectiveidea/audited) see []()
|
4
5
|
|
5
|
-
|
6
|
+
## Supported ORMs
|
6
7
|
|
7
|
-
|
8
|
+
Currently only supports ActiveRecord.
|
8
9
|
|
9
|
-
|
10
|
+
## Instalation
|
11
|
+
|
12
|
+
Add to your Gemfile:
|
13
|
+
|
14
|
+
``` ruby
|
15
|
+
gem 'rails_log_book'
|
16
|
+
```
|
17
|
+
|
18
|
+
Then run:
|
10
19
|
|
11
20
|
```ruby
|
12
|
-
|
21
|
+
rails generate log_book:install
|
22
|
+
rake db:migrate
|
13
23
|
```
|
14
24
|
|
15
|
-
|
25
|
+
## Usage
|
16
26
|
|
17
|
-
|
27
|
+
Add to models you want to keep track of:
|
18
28
|
|
19
|
-
|
29
|
+
``` ruby
|
30
|
+
class User < ActiveRecord::Base
|
31
|
+
include LogBook::Recorder
|
20
32
|
|
21
|
-
|
33
|
+
has_log_book_records
|
34
|
+
end
|
35
|
+
```
|
22
36
|
|
23
|
-
|
37
|
+
Add to controlers and actions you want the tracker to be active:
|
38
|
+
|
39
|
+
``` ruby
|
40
|
+
class UsersController < ApplicationController
|
41
|
+
include LogBook::ControllerRecord
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
By default, whenever a user record is created, updated or deleted in any actions of users\_controller a new log\_book record will be created.
|
46
|
+
|
47
|
+
## ActiveRecord Options
|
48
|
+
|
49
|
+
### fields
|
50
|
+
|
51
|
+
``` ruby
|
52
|
+
class User < ActiveRecord::Base
|
53
|
+
include LogBook::Recorder
|
54
|
+
|
55
|
+
# all fields
|
56
|
+
# has_log_book_records
|
24
57
|
|
25
|
-
|
58
|
+
# Only fields
|
59
|
+
# has_log_book_records only: [:email, :name]
|
60
|
+
|
61
|
+
# Ignored fields
|
62
|
+
# has_log_book_records except: [:password]
|
63
|
+
|
64
|
+
# Default ignored fields
|
65
|
+
# primary_key (id), LogBook.config.ignored_attributes (:created_at, :updated_at)
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
### callbacks
|
70
|
+
|
71
|
+
``` ruby
|
72
|
+
class User < ActiveRecord::Base
|
73
|
+
include LogBook::Recorder
|
74
|
+
|
75
|
+
# all events
|
76
|
+
# has_log_book_records
|
77
|
+
|
78
|
+
# Only record on create and destroy (not update)
|
79
|
+
# has_log_book_records on: [:create, :destroy]
|
80
|
+
end
|
81
|
+
```
|
82
|
+
|
83
|
+
### parent
|
84
|
+
|
85
|
+
Define who is a parent of this object. Will be recorded in a `parent` polymorphic columns
|
86
|
+
|
87
|
+
``` ruby
|
88
|
+
class User < ActiveRecord::Base
|
89
|
+
include LogBook::Recorder
|
90
|
+
belongs_to :company
|
91
|
+
|
92
|
+
# Parent is Company and will be recorded with each user change
|
93
|
+
# has_log_book_records parent: :company
|
94
|
+
end
|
95
|
+
```
|
26
96
|
|
97
|
+
### meta
|
98
|
+
|
99
|
+
Arbitrary column. This is a jsonb field which can have all kinds of information. Useful when you want to cache fields at the exact point of record creation
|
100
|
+
|
101
|
+
``` ruby
|
102
|
+
class User < ActiveRecord::Base
|
103
|
+
include LogBook::Recorder
|
104
|
+
|
105
|
+
# runs `log_book_meta(record)` method to assign to `:meta` field
|
106
|
+
# has_log_book_records meta: true
|
107
|
+
|
108
|
+
# runs `meta_method` method to assing to `:meta` field
|
109
|
+
# has_log_book_records meta: :meta_method
|
110
|
+
|
111
|
+
# runs passed proc to assing to `:meta` field
|
112
|
+
# has_log_book_records meta: -> { { slug: email.split('@').first } }
|
113
|
+
end
|
114
|
+
```
|
115
|
+
|
116
|
+
### squash
|
117
|
+
|
118
|
+
Enables/disables suashing on this model
|
119
|
+
|
120
|
+
``` ruby
|
121
|
+
class User < ActiveRecord::Base
|
122
|
+
include LogBook::Recorder
|
123
|
+
|
124
|
+
# Enables squashing (defaults to false)
|
125
|
+
# has_log_book_records squash: true
|
126
|
+
```
|
127
|
+
|
128
|
+
## ActionController options
|
129
|
+
|
130
|
+
### current\_author
|
131
|
+
|
132
|
+
Defines what method is run when looking for the author for recording
|
133
|
+
|
134
|
+
``` ruby
|
135
|
+
class Admin::UsersController < ActionController::Base
|
136
|
+
inlcude LogBook::ControllerRecord
|
137
|
+
|
138
|
+
# defaults to `current_user`
|
139
|
+
def current_author
|
140
|
+
current_admin
|
141
|
+
end
|
142
|
+
```
|
143
|
+
|
144
|
+
## Configuration
|
145
|
+
|
146
|
+
``` ruby
|
147
|
+
# config/initializers/log_book.rb
|
148
|
+
LogBook.configure do |config|
|
149
|
+
config.records_table_name = 'records'
|
150
|
+
config.ignored_attributes = [:updated_at, :created_at]
|
151
|
+
config.author_method = :current_user
|
152
|
+
config.record_squashing = false
|
153
|
+
config.recording_enabled = false
|
154
|
+
config.skip_if_empty_actions = [:update]
|
155
|
+
end
|
156
|
+
```
|
157
|
+
|
158
|
+
## Additional methods
|
159
|
+
|
160
|
+
``` ruby
|
161
|
+
LogBook.with_recording {} #=> Enables recording within block
|
162
|
+
LogBook.without_recording {} #=> Disables recording within block
|
163
|
+
LogBook.record_as(author) {} #=> Records as a different author within block
|
164
|
+
LogBook.with_record_squashing {} #=> Squashes records within block
|
165
|
+
LogBook.enable_recording #=> Enables recording from this point
|
166
|
+
LogBook.disable_recording #=> Disables recording from this point
|
167
|
+
LogBook.record_squashing_enabled #=> Enables record squashing from this point
|
168
|
+
LogBook.recording_enabled #=> Returns true if recording is enabled
|
169
|
+
LogBook.recording_enabled=(val) #=> Enables/Disables recording
|
170
|
+
LogBook.squash_records #=> Squash records with current :request_uuid
|
171
|
+
```
|
172
|
+
|
173
|
+
## Squashing
|
174
|
+
|
175
|
+
The idea of squashing came when we needed to show an activity page where all changes made in the single request as one change.
|
176
|
+
|
177
|
+
Each request has its own unique `request_uuid` and it is recorded with each record. If squashing is enabled, `after_action` method with squashing is called.
|
178
|
+
All records with the same `request_uuid` are "squashed" into one record.
|
179
|
+
|
180
|
+
``` sql
|
181
|
+
INSERT INTO "users" ("name", "email") VALUES ("test", "test@test.com")
|
182
|
+
```
|
27
183
|
## Development
|
28
184
|
|
29
185
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -32,7 +188,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
32
188
|
|
33
189
|
## Contributing
|
34
190
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
191
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/infinum/log_book. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
36
192
|
|
37
193
|
|
38
194
|
## License
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'rails/generators/migration'
|
2
2
|
require 'generators/log_book/migration'
|
3
|
-
require '
|
3
|
+
require 'rails_log_book'
|
4
4
|
|
5
5
|
module LogBook
|
6
6
|
module Generators
|
@@ -17,6 +17,12 @@ module LogBook
|
|
17
17
|
def copy_migration
|
18
18
|
migration_template 'install.rb', 'db/migrate/install_log_book.rb'
|
19
19
|
end
|
20
|
+
|
21
|
+
def migration_version
|
22
|
+
if rails5?
|
23
|
+
"[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]"
|
24
|
+
end
|
25
|
+
end
|
20
26
|
end
|
21
27
|
end
|
22
28
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class <%= migration_class_name %> < ActiveRecord::Migration
|
1
|
+
class <%= migration_class_name %> < ActiveRecord::Migration<%= migration_version %>
|
2
2
|
def change
|
3
3
|
create_table :records do |t|
|
4
4
|
t.belongs_to :author, polymorphic: true, index: true
|
@@ -6,7 +6,7 @@ class <%= migration_class_name %> < ActiveRecord::Migration
|
|
6
6
|
t.belongs_to :parent, polymorphic: true, index: true
|
7
7
|
t.jsonb :record_changes, default: {}
|
8
8
|
t.jsonb :meta, default: {}
|
9
|
-
t.string :request_uuid
|
9
|
+
t.string :request_uuid, index: true
|
10
10
|
t.string :action
|
11
11
|
|
12
12
|
t.datetime :created_at
|
@@ -21,7 +21,7 @@ module LogBook
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def current_author
|
24
|
-
raise NotImplementedError unless respond_to?(LogBook.config.author_method)
|
24
|
+
raise NotImplementedError unless respond_to?(LogBook.config.author_method, true)
|
25
25
|
send(LogBook.config.author_method)
|
26
26
|
end
|
27
27
|
end
|
data/lib/log_book/recorder.rb
CHANGED
@@ -34,19 +34,6 @@ module LogBook
|
|
34
34
|
self.class.with_recording(&block)
|
35
35
|
end
|
36
36
|
|
37
|
-
def new_record
|
38
|
-
record = LogBook::Record.new(
|
39
|
-
action: LogBook.store[:action],
|
40
|
-
record_changes: record_changes,
|
41
|
-
author: LogBook.store[:author],
|
42
|
-
subject: self,
|
43
|
-
meta: {}
|
44
|
-
)
|
45
|
-
record.meta = log_book_meta_info(record) if recording_options[:meta].present?
|
46
|
-
record.parent = send(recording_options[:parent]) if recording_options[:parent].present?
|
47
|
-
record
|
48
|
-
end
|
49
|
-
|
50
37
|
def recording_attributes
|
51
38
|
attributes.except(*non_recording_columns)
|
52
39
|
end
|
@@ -60,9 +47,9 @@ module LogBook
|
|
60
47
|
def record_changes
|
61
48
|
if recording_options[:only]
|
62
49
|
recording_columns = self.class.recording_columns.map(&:name)
|
63
|
-
|
50
|
+
saved_changes.slice(*recording_columns)
|
64
51
|
else
|
65
|
-
|
52
|
+
saved_changes.except(*non_recording_columns)
|
66
53
|
end
|
67
54
|
end
|
68
55
|
|
@@ -80,12 +67,24 @@ module LogBook
|
|
80
67
|
|
81
68
|
def write_record(action)
|
82
69
|
return unless LogBook.recording_enabled
|
83
|
-
LogBook.store[:action]
|
84
|
-
record = new_record
|
70
|
+
record = new_record(LogBook.store[:action] || action)
|
85
71
|
return unless record.changes_to_record?
|
86
72
|
record.save
|
87
73
|
end
|
88
74
|
|
75
|
+
def new_record(action)
|
76
|
+
record = LogBook::Record.new(
|
77
|
+
action: action,
|
78
|
+
record_changes: record_changes,
|
79
|
+
author: LogBook.store[:author],
|
80
|
+
subject: self,
|
81
|
+
meta: {}
|
82
|
+
)
|
83
|
+
record.meta = log_book_meta_info(record) if recording_options[:meta].present?
|
84
|
+
record.parent = send(recording_options[:parent]) if recording_options[:parent].present?
|
85
|
+
record
|
86
|
+
end
|
87
|
+
|
89
88
|
def log_book_meta_info(record)
|
90
89
|
case recording_options[:meta]
|
91
90
|
when NilClass then nil
|
@@ -6,17 +6,28 @@ module LogBook
|
|
6
6
|
|
7
7
|
def call
|
8
8
|
records.group_by(&:parent).each do |parent, children|
|
9
|
-
next if parent.nil?
|
10
9
|
children_to_squash = children.select { |child| child.subject.try(:to_squash?) }
|
11
10
|
next if children_to_squash.empty?
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
if parent.present?
|
13
|
+
parent_in_records = parent_in_records(parent)
|
14
|
+
parent_in_records.record_changes.merge!(squashed_changes(children_to_squash, :record_changes))
|
15
|
+
parent_in_records.meta.merge!(squashed_changes(children_to_squash, :meta))
|
16
|
+
parent_in_records.created_at ||= children_to_squash.first.created_at
|
17
|
+
parent_in_records.save
|
18
18
|
|
19
|
-
|
19
|
+
children_to_squash.each(&:delete)
|
20
|
+
else
|
21
|
+
next if children_to_squash.one?
|
22
|
+
|
23
|
+
records.reduce do |main_record, record|
|
24
|
+
main_record.record_changes.merge!(record.record_changes)
|
25
|
+
main_record.meta.merge!(record.meta)
|
26
|
+
|
27
|
+
record.delete
|
28
|
+
main_record
|
29
|
+
end.save
|
30
|
+
end
|
20
31
|
end
|
21
32
|
end
|
22
33
|
|
data/lib/log_book/version.rb
CHANGED
data/log_book.gemspec
CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |spec|
|
|
6
6
|
spec.name = 'rails_log_book'
|
7
7
|
spec.version = LogBook::VERSION
|
8
8
|
spec.authors = ['Stjepan Hadjic']
|
9
|
-
spec.email = ['
|
9
|
+
spec.email = ['stjepan.hadjic@infinum.co']
|
10
10
|
|
11
11
|
spec.summary = 'Write a short summary, because Rubygems requires one.'
|
12
12
|
spec.description = 'Write a longer description or delete this line.'
|
@@ -32,5 +32,5 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.add_development_dependency 'pry-byebug'
|
33
33
|
|
34
34
|
spec.add_dependency 'request_store'
|
35
|
-
spec.add_dependency 'activerecord', '
|
35
|
+
spec.add_dependency 'activerecord', '> 5.2'
|
36
36
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_log_book
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stjepan Hadjic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-09-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -112,25 +112,19 @@ dependencies:
|
|
112
112
|
name: activerecord
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
|
-
- - "
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '4.0'
|
118
|
-
- - "<"
|
115
|
+
- - ">"
|
119
116
|
- !ruby/object:Gem::Version
|
120
|
-
version: '5.
|
117
|
+
version: '5.2'
|
121
118
|
type: :runtime
|
122
119
|
prerelease: false
|
123
120
|
version_requirements: !ruby/object:Gem::Requirement
|
124
121
|
requirements:
|
125
|
-
- - "
|
126
|
-
- !ruby/object:Gem::Version
|
127
|
-
version: '4.0'
|
128
|
-
- - "<"
|
122
|
+
- - ">"
|
129
123
|
- !ruby/object:Gem::Version
|
130
|
-
version: '5.
|
124
|
+
version: '5.2'
|
131
125
|
description: Write a longer description or delete this line.
|
132
126
|
email:
|
133
|
-
-
|
127
|
+
- stjepan.hadjic@infinum.co
|
134
128
|
executables: []
|
135
129
|
extensions: []
|
136
130
|
extra_rdoc_files: []
|
@@ -180,7 +174,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
180
174
|
version: '0'
|
181
175
|
requirements: []
|
182
176
|
rubyforge_project:
|
183
|
-
rubygems_version: 2.
|
177
|
+
rubygems_version: 2.7.3
|
184
178
|
signing_key:
|
185
179
|
specification_version: 4
|
186
180
|
summary: Write a short summary, because Rubygems requires one.
|