rails_audit_log 0.6.0 → 0.8.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
  SHA256:
3
- metadata.gz: 6cc56d9335d26c5f43d52de380aa354a268cbb266696799cf1775f051162c2d8
4
- data.tar.gz: '027792cdf8815ec2822177492b674d05534a3d96163d463dd603a415d471ace2'
3
+ metadata.gz: 5cd71899d109aa978910a72ef144aeafb601dc70790e044ef723b49d1d560f65
4
+ data.tar.gz: 8884deec2a0abf63f14639794d6ac614689c9799e09b375ffc0cc7d788943e7d
5
5
  SHA512:
6
- metadata.gz: 107247da00cc1f7eec9750f9d59eb2b41fa47f4ec9c3a0b00f587882bf6080250fe5af5152a2d13491fdb6ebf6aa7d3f82a6418f89777b9dca3819c024692805
7
- data.tar.gz: 3715691ec2538d7fca5538af23e9f087899469876dcb98b660d82f18230ee531f45660950c95e4230f15a6a430b4b85999691472b9c61cf1d4e88af6c90849c2
6
+ metadata.gz: c32ada5189eda30461ea1dbc10a67982fb0ff6c4244da4339aa3376082b38a5272bb3a1b91fe50110c08ae9ee0ae3ede52d2a43701c0f7260a4d5a6581c0f42d
7
+ data.tar.gz: 448becbb80428dd754bca4d1ab43625de5ec85a2c9d712e9e4a28f7c14b0c18ce6865b25dfd9ea6c46f7b1814988d0eea77ae8b6aee7a230927cc37a80f60cf3
data/README.md CHANGED
@@ -23,6 +23,14 @@ bin/rails generate rails_audit_log:install
23
23
  bin/rails db:migrate
24
24
  ```
25
25
 
26
+ Optionally scaffold a commented initializer with every configuration option:
27
+
28
+ ```bash
29
+ bin/rails generate rails_audit_log:initializer
30
+ ```
31
+
32
+ This creates `config/initializers/rails_audit_log.rb` with all settings documented as commented examples inside a `RailsAuditLog.configure` block.
33
+
26
34
  ## Usage
27
35
 
28
36
  ### Tracking a model
@@ -102,6 +110,32 @@ entry.diff
102
110
  # => { "title" => { from: "Hello", to: "World" } }
103
111
  ```
104
112
 
113
+ ### Separate audit database
114
+
115
+ Route all audit writes to a dedicated database by setting `connects_to` in an initializer. The engine applies it to `AuditLogEntry` at boot:
116
+
117
+ ```ruby
118
+ # config/initializers/rails_audit_log.rb
119
+ RailsAuditLog.connects_to = {
120
+ database: { writing: :audit_log, reading: :audit_log }
121
+ }
122
+ ```
123
+
124
+ The key (e.g. `:audit_log`) must match a database key in `config/database.yml`. All reads and writes on `AuditLogEntry` — including `batch_audit` inserts and `WriteAuditLogJob` — use that connection automatically.
125
+
126
+ ### Lightweight queries
127
+
128
+ Use `.slim` to exclude the three JSON blob columns (`object_changes`, `object`, `metadata`) from the SQL projection. This is useful for index or listing views where you only need the entry header (who, what event, when):
129
+
130
+ ```ruby
131
+ entries = AuditLogEntry.slim.for_resource(article).since(1.week.ago)
132
+ entries.first.event # => "update"
133
+ entries.first.actor_type # => "User"
134
+ entries.first.object_changes # => raises ActiveModel::MissingAttributeError
135
+ ```
136
+
137
+ > **Note:** Use `.count(:id)` instead of `.count` when chaining `.slim` with other scopes — Rails' `COUNT` with a multi-column `SELECT` is not supported by all databases.
138
+
105
139
  ### Association tracking
106
140
 
107
141
  Track `has_many` add and remove events by passing `associations: true` to `audit_log`. Call `audit_log` **before** the `has_many` declarations so the callbacks are wired at class load time:
@@ -151,6 +185,59 @@ end
151
185
 
152
186
  `belongs_to` foreign-key changes are already tracked as regular column updates and require no extra configuration.
153
187
 
188
+ ### Bulk audit writes
189
+
190
+ Wrap a block with `RailsAuditLog.batch_audit` to buffer all audit entries and flush them in a single `insert_all!` call at the end, eliminating N+1 inserts during imports:
191
+
192
+ ```ruby
193
+ RailsAuditLog.batch_audit do
194
+ records.each { |attrs| Post.create!(attrs) }
195
+ end
196
+ # All audit entries written in one INSERT
197
+ ```
198
+
199
+ Nested calls accumulate into the outermost batch — only one `insert_all!` fires. If the block raises, the buffer is discarded and no entries are written.
200
+
201
+ > **Note:** Version pruning (`version_limit`) is deferred in batch mode — the next write outside the batch will trigger pruning as usual.
202
+
203
+ ### Async audit writes
204
+
205
+ Offload audit writes to a background job by passing `async: true` to `audit_log`. The entry is enqueued via `RailsAuditLog::WriteAuditLogJob` (a subclass of `ActiveJob::Base`) so the request does not block on the database write:
206
+
207
+ ```ruby
208
+ class Post < ApplicationRecord
209
+ include RailsAuditLog::Auditable
210
+ audit_log async: true
211
+ end
212
+ ```
213
+
214
+ Enable async globally in an initializer — per-model `async: true` takes precedence:
215
+
216
+ ```ruby
217
+ # config/initializers/rails_audit_log.rb
218
+ RailsAuditLog.async = true
219
+ ```
220
+
221
+ Configure the queue adapter and queue name through standard ActiveJob settings. Version pruning also runs inside the job when `version_limit` is set.
222
+
223
+ ### Capping history per record
224
+
225
+ Limit how many audit entries are kept per record with `version_limit:`. Oldest entries are pruned automatically after each write once the cap is reached:
226
+
227
+ ```ruby
228
+ class Post < ApplicationRecord
229
+ include RailsAuditLog::Auditable
230
+ audit_log version_limit: 10 # keep only the 10 most recent entries
231
+ end
232
+ ```
233
+
234
+ Set a global default in an initializer — per-model values take precedence:
235
+
236
+ ```ruby
237
+ # config/initializers/rails_audit_log.rb
238
+ RailsAuditLog.version_limit = 50
239
+ ```
240
+
154
241
  ### Selective tracking
155
242
 
156
243
  Track only specific attributes, or exclude noisy ones:
@@ -305,6 +392,76 @@ To save storage at the cost of reduced reification accuracy, switch to diff-only
305
392
  RailsAuditLog.store_snapshot = false
306
393
  ```
307
394
 
395
+ ### Test helper
396
+
397
+ `without_audit_log` silences audit tracking inside the block — useful in FactoryBot factories and seed data to avoid noise in the audit trail:
398
+
399
+ ```ruby
400
+ # spec/rails_helper.rb (or spec/support/factory_helpers.rb)
401
+ require "rails_audit_log/test_helpers"
402
+
403
+ RSpec.configure do |config|
404
+ config.include RailsAuditLog::TestHelpers
405
+ end
406
+
407
+ # Or include directly in FactoryBot definitions:
408
+ FactoryBot.define do
409
+ factory :post do
410
+ after(:create) { |p| without_audit_log { p.update!(cached_at: Time.current) } }
411
+ end
412
+ end
413
+ ```
414
+
415
+ `without_audit_log` is a prefix-free wrapper around `RailsAuditLog.disable` — thread-safe and restores tracking even if the block raises.
416
+
417
+ ### Minitest assertions
418
+
419
+ Add to your `test/test_helper.rb`:
420
+
421
+ ```ruby
422
+ require "rails_audit_log/minitest_assertions"
423
+
424
+ class ActiveSupport::TestCase
425
+ include RailsAuditLog::MinitestAssertions
426
+ end
427
+ ```
428
+
429
+ Then use the assertions in any test:
430
+
431
+ ```ruby
432
+ assert_audit_log_entry post # any entry
433
+ assert_audit_log_entry post, event: :update # update entry
434
+ assert_audit_log_entry post, event: :update, touching: :title # touching title
435
+ refute_audit_log_entry post, event: :update # no update entry
436
+ assert_audit_log_entry post, event: :update, message: "custom" # custom failure message
437
+ ```
438
+
439
+ ### RSpec matchers
440
+
441
+ Add to your `spec/rails_helper.rb` (or `spec_helper.rb`):
442
+
443
+ ```ruby
444
+ require "rails_audit_log/matchers"
445
+
446
+ RSpec.configure do |config|
447
+ config.include RailsAuditLog::Matchers
448
+ end
449
+ ```
450
+
451
+ Then use the matchers in any spec:
452
+
453
+ ```ruby
454
+ # Assert a record has a matching audit entry
455
+ expect(post).to have_audit_log_entry
456
+ expect(post).to have_audit_log_entry(:update)
457
+ expect(post).to have_audit_log_entry(:update).touching(:title)
458
+
459
+ # Assert a block creates a matching audit entry
460
+ expect { post.update!(title: "New") }.to create_audit_log_entry
461
+ expect { post.update!(title: "New") }.to create_audit_log_entry(event: :update)
462
+ expect { post.update!(title: "New") }.to create_audit_log_entry(event: :update).touching(:title)
463
+ ```
464
+
308
465
  ## Requirements
309
466
 
310
467
  - Ruby >= 3.3
@@ -3,10 +3,14 @@ module RailsAuditLog
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- class_attribute :_audit_log_only, default: nil
7
- class_attribute :_audit_log_ignore, default: nil
8
- class_attribute :_audit_log_meta, default: nil
9
- class_attribute :_audit_log_associations, default: nil
6
+ class_attribute :_audit_log_only, default: nil
7
+ class_attribute :_audit_log_ignore, default: nil
8
+ class_attribute :_audit_log_meta, default: nil
9
+ class_attribute :_audit_log_associations, default: nil
10
+ class_attribute :_audit_log_version_limit, default: nil
11
+ class_attribute :_audit_log_async, default: false
12
+
13
+ _warn_if_audit_table_missing
10
14
 
11
15
  has_many :audit_log_entries,
12
16
  class_name: "RailsAuditLog::AuditLogEntry",
@@ -50,11 +54,25 @@ module RailsAuditLog
50
54
  end
51
55
 
52
56
  class_methods do
53
- def audit_log(only: nil, ignore: nil, meta: nil, associations: nil)
54
- self._audit_log_only = only.map(&:to_s) if only
55
- self._audit_log_ignore = ignore.map(&:to_s) if ignore
56
- self._audit_log_meta = meta if meta
57
- self._audit_log_associations = associations unless associations.nil?
57
+ def _warn_if_audit_table_missing
58
+ return if connection.table_exists?("audit_log_entries")
59
+
60
+ warn "[RailsAuditLog] WARNING: #{name} includes RailsAuditLog::Auditable but the " \
61
+ "'audit_log_entries' table does not exist. " \
62
+ "Run `bin/rails generate rails_audit_log:install && bin/rails db:migrate` to create it."
63
+ rescue ActiveRecord::NoDatabaseError,
64
+ ActiveRecord::ConnectionNotEstablished,
65
+ ActiveRecord::StatementInvalid
66
+ # DB not reachable during this phase (e.g. before db:create) — skip the check
67
+ end
68
+
69
+ def audit_log(only: nil, ignore: nil, meta: nil, associations: nil, version_limit: nil, async: nil)
70
+ self._audit_log_only = only.map(&:to_s) if only
71
+ self._audit_log_ignore = ignore.map(&:to_s) if ignore
72
+ self._audit_log_meta = meta if meta
73
+ self._audit_log_associations = associations unless associations.nil?
74
+ self._audit_log_version_limit = version_limit unless version_limit.nil?
75
+ self._audit_log_async = async unless async.nil?
58
76
  end
59
77
  end
60
78
 
@@ -84,11 +102,12 @@ module RailsAuditLog
84
102
 
85
103
  actor = RailsAuditLog.actor
86
104
  meta = build_audit_metadata
87
- RailsAuditLog::AuditLogEntry.create!(
105
+ write_audit_entry(
88
106
  event: "update",
89
107
  item_type: self.class.name,
90
108
  item_id: id,
91
109
  object_changes: { assoc_name => [before, after] },
110
+ object: nil,
92
111
  reason: RailsAuditLog.reason,
93
112
  metadata: meta.presence,
94
113
  whodunnit_snapshot: actor ? RailsAuditLog.whodunnit_display.call(actor) : nil,
@@ -104,8 +123,8 @@ module RailsAuditLog
104
123
  return if filtered.empty? && event == "update"
105
124
 
106
125
  actor = RailsAuditLog.actor
107
- meta = build_audit_metadata
108
- RailsAuditLog::AuditLogEntry.create!(
126
+ meta = build_audit_metadata
127
+ write_audit_entry(
109
128
  event: event,
110
129
  item_type: self.class.name,
111
130
  item_id: id,
@@ -119,6 +138,29 @@ module RailsAuditLog
119
138
  )
120
139
  end
121
140
 
141
+ def write_audit_entry(entry_attrs)
142
+ if (buffer = RailsAuditLog.batch_audit_buffer)
143
+ buffer << entry_attrs.stringify_keys.merge("created_at" => Time.current)
144
+ elsif _audit_log_async || RailsAuditLog.async
145
+ limit = self.class._audit_log_version_limit || RailsAuditLog.version_limit
146
+ WriteAuditLogJob.perform_later(entry_attrs.stringify_keys, version_limit: limit)
147
+ else
148
+ RailsAuditLog::AuditLogEntry.create!(entry_attrs)
149
+ prune_audit_entries
150
+ end
151
+ end
152
+
153
+ def prune_audit_entries
154
+ limit = self.class._audit_log_version_limit || RailsAuditLog.version_limit
155
+ return unless limit
156
+
157
+ count = audit_log_entries.count
158
+ excess = count - limit
159
+ return unless excess > 0
160
+
161
+ audit_log_entries.order(id: :asc).limit(excess).delete_all
162
+ end
163
+
122
164
  def build_audit_metadata
123
165
  meta = {}
124
166
  if self.class._audit_log_meta
@@ -0,0 +1,20 @@
1
+ module RailsAuditLog
2
+ class WriteAuditLogJob < ApplicationJob
3
+ def perform(entry_attrs, version_limit: nil)
4
+ AuditLogEntry.create!(entry_attrs)
5
+
6
+ return unless version_limit
7
+
8
+ item_type = entry_attrs["item_type"]
9
+ item_id = entry_attrs["item_id"]
10
+ count = AuditLogEntry.where(item_type: item_type, item_id: item_id).count
11
+ excess = count - version_limit
12
+ return unless excess > 0
13
+
14
+ AuditLogEntry.where(item_type: item_type, item_id: item_id)
15
+ .order(id: :asc)
16
+ .limit(excess)
17
+ .delete_all
18
+ end
19
+ end
20
+ end
@@ -3,6 +3,13 @@ module RailsAuditLog
3
3
  self.table_name = "audit_log_entries"
4
4
 
5
5
  EVENTS = %w[create update destroy].freeze
6
+ BLOB_COLUMNS = %w[object_changes object metadata].freeze
7
+
8
+ def self.configure_connection!
9
+ return unless (opts = RailsAuditLog.connects_to)
10
+
11
+ connects_to(**opts)
12
+ end
6
13
 
7
14
  belongs_to :item, polymorphic: true, optional: true
8
15
  belongs_to :actor, polymorphic: true, optional: true
@@ -37,6 +44,9 @@ module RailsAuditLog
37
44
  scope :since, ->(time) { where(created_at: time..) }
38
45
  scope :until, ->(time) { where(created_at: ..time) }
39
46
 
47
+ # Projection scope — omits JSON blob columns for index/listing queries
48
+ scope :slim, -> { select(column_names - BLOB_COLUMNS) }
49
+
40
50
  # Instance methods
41
51
 
42
52
  def reify
@@ -0,0 +1,15 @@
1
+ require "rails/generators"
2
+
3
+ module RailsAuditLog
4
+ module Generators
5
+ class InitializerGenerator < Rails::Generators::Base
6
+ source_root File.expand_path("templates", __dir__)
7
+
8
+ desc "Creates a commented RailsAuditLog initializer in config/initializers."
9
+
10
+ def create_initializer_file
11
+ template "rails_audit_log.rb", "config/initializers/rails_audit_log.rb"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,31 @@
1
+ # config/initializers/rails_audit_log.rb
2
+ # Generated by `bin/rails generate rails_audit_log:initializer`
3
+ #
4
+ # All settings are optional. Remove the comments around any line you want to activate.
5
+
6
+ RailsAuditLog.configure do |config|
7
+ # Global columns excluded from all audited models. Default: ["updated_at"]
8
+ # config.ignored_attributes = %w[updated_at cached_at]
9
+
10
+ # Store a full attribute snapshot alongside object_changes. Default: true
11
+ # Disable to save storage; reify and version_at fall back to diff-only reconstruction.
12
+ # config.store_snapshot = false
13
+
14
+ # Capture remote_ip and user_agent into each entry's metadata column. Default: false
15
+ # Requires including RailsAuditLog::Controller in ApplicationController.
16
+ # config.capture_request_metadata = true
17
+
18
+ # Customise how the actor's display name is stored at write time. Default: actor.name
19
+ # config.whodunnit_display = ->(actor) { actor.email }
20
+
21
+ # Global cap on entries retained per tracked record. Default: nil (no limit)
22
+ # Per-model `audit_log version_limit: N` takes precedence.
23
+ # config.version_limit = 100
24
+
25
+ # Write all audit entries asynchronously via WriteAuditLogJob. Default: false
26
+ # Per-model `audit_log async: true` also works.
27
+ # config.async = true
28
+
29
+ # Route AuditLogEntry to a dedicated database (Rails multi-DB). Default: nil
30
+ # config.connects_to = { database: { writing: :audit_log, reading: :audit_log } }
31
+ end
@@ -1,5 +1,11 @@
1
1
  module RailsAuditLog
2
2
  class Engine < ::Rails::Engine
3
3
  isolate_namespace RailsAuditLog
4
+
5
+ initializer "rails_audit_log.connect_audit_db" do
6
+ ActiveSupport.on_load(:active_record) do
7
+ RailsAuditLog::AuditLogEntry.configure_connection!
8
+ end
9
+ end
4
10
  end
5
11
  end
@@ -0,0 +1,103 @@
1
+ module RailsAuditLog
2
+ module Matchers
3
+ def have_audit_log_entry(event = nil)
4
+ HaveAuditLogEntry.new(event)
5
+ end
6
+
7
+ def create_audit_log_entry(event: nil, touching: nil)
8
+ CreateAuditLogEntry.new(event: event, touching: touching)
9
+ end
10
+
11
+ class HaveAuditLogEntry
12
+ def initialize(event)
13
+ @event = event
14
+ @touching = nil
15
+ end
16
+
17
+ def touching(attribute)
18
+ @touching = attribute
19
+ self
20
+ end
21
+
22
+ def matches?(record)
23
+ @record = record
24
+ scope = record.audit_log_entries
25
+ scope = scope.where(event: @event.to_s) if @event
26
+ scope = scope.touching(@touching) if @touching
27
+ scope.exists?
28
+ end
29
+
30
+ def failure_message
31
+ "expected #{@record.class}##{@record.id} to have an audit log entry#{qualifier}"
32
+ end
33
+
34
+ def failure_message_when_negated
35
+ "expected #{@record.class}##{@record.id} not to have an audit log entry#{qualifier}"
36
+ end
37
+
38
+ def description
39
+ "have an audit log entry#{qualifier}"
40
+ end
41
+
42
+ private
43
+
44
+ def qualifier
45
+ parts = []
46
+ parts << " with event '#{@event}'" if @event
47
+ parts << " touching '#{@touching}'" if @touching
48
+ parts.join
49
+ end
50
+ end
51
+
52
+ class CreateAuditLogEntry
53
+ def initialize(event:, touching:)
54
+ @event = event
55
+ @touching = touching
56
+ end
57
+
58
+ def touching(attribute)
59
+ @touching = attribute
60
+ self
61
+ end
62
+
63
+ def supports_block_expectations?
64
+ true
65
+ end
66
+
67
+ def matches?(block)
68
+ @before = matching_scope.count
69
+ block.call
70
+ @after = matching_scope.count
71
+ @after > @before
72
+ end
73
+
74
+ def failure_message
75
+ "expected block to create an audit log entry#{qualifier}, but none was created"
76
+ end
77
+
78
+ def failure_message_when_negated
79
+ "expected block not to create an audit log entry#{qualifier}, but one was created"
80
+ end
81
+
82
+ def description
83
+ "create an audit log entry#{qualifier}"
84
+ end
85
+
86
+ private
87
+
88
+ def matching_scope
89
+ scope = RailsAuditLog::AuditLogEntry.all
90
+ scope = scope.where(event: @event.to_s) if @event
91
+ scope = scope.touching(@touching) if @touching
92
+ scope
93
+ end
94
+
95
+ def qualifier
96
+ parts = []
97
+ parts << " with event '#{@event}'" if @event
98
+ parts << " touching '#{@touching}'" if @touching
99
+ parts.join
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,31 @@
1
+ module RailsAuditLog
2
+ module MinitestAssertions
3
+ def assert_audit_log_entry(record, event: nil, touching: nil, message: nil)
4
+ scope = build_scope(record, event, touching)
5
+ msg = message || default_message("to have", record, event, touching)
6
+ assert scope.exists?, msg
7
+ end
8
+
9
+ def refute_audit_log_entry(record, event: nil, touching: nil, message: nil)
10
+ scope = build_scope(record, event, touching)
11
+ msg = message || default_message("not to have", record, event, touching)
12
+ refute scope.exists?, msg
13
+ end
14
+
15
+ private
16
+
17
+ def build_scope(record, event, touching)
18
+ scope = record.audit_log_entries
19
+ scope = scope.where(event: event.to_s) if event
20
+ scope = scope.touching(touching) if touching
21
+ scope
22
+ end
23
+
24
+ def default_message(polarity, record, event, touching)
25
+ parts = []
26
+ parts << " with event '#{event}'" if event
27
+ parts << " touching '#{touching}'" if touching
28
+ "Expected #{record.class}##{record.id} #{polarity} an audit log entry#{parts.join}"
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,7 @@
1
+ module RailsAuditLog
2
+ module TestHelpers
3
+ def without_audit_log(&block)
4
+ RailsAuditLog.disable(&block)
5
+ end
6
+ end
7
+ end
@@ -1,3 +1,3 @@
1
1
  module RailsAuditLog
2
- VERSION = "0.6.0"
2
+ VERSION = "0.8.0"
3
3
  end
@@ -5,8 +5,15 @@ module RailsAuditLog
5
5
  # Global default columns to ignore across all audited models.
6
6
  # Override in an initializer: RailsAuditLog.ignored_attributes = %w[updated_at cached_at]
7
7
  mattr_accessor :ignored_attributes, default: %w[updated_at]
8
+
9
+ def self.configure
10
+ yield self
11
+ end
8
12
  mattr_accessor :store_snapshot, default: true
9
13
  mattr_accessor :capture_request_metadata, default: false
14
+ mattr_accessor :version_limit, default: nil
15
+ mattr_accessor :async, default: false
16
+ mattr_accessor :connects_to, default: nil
10
17
  mattr_accessor :whodunnit_display, default: ->(actor) {
11
18
  actor.respond_to?(:name) ? actor.name.to_s : actor.to_s
12
19
  }
@@ -63,6 +70,24 @@ module RailsAuditLog
63
70
  self.reason = previous
64
71
  end
65
72
 
73
+ def self.batch_audit
74
+ return yield if Thread.current[:rails_audit_log_batch]
75
+
76
+ Thread.current[:rails_audit_log_batch] = []
77
+ begin
78
+ result = yield
79
+ batch = Thread.current[:rails_audit_log_batch]
80
+ AuditLogEntry.insert_all!(batch) if batch.any?
81
+ result
82
+ ensure
83
+ Thread.current[:rails_audit_log_batch] = nil
84
+ end
85
+ end
86
+
87
+ def self.batch_audit_buffer
88
+ Thread.current[:rails_audit_log_batch]
89
+ end
90
+
66
91
  def self.version_at(record, time)
67
92
  entry = AuditLogEntry
68
93
  .where(item_type: record.class.name, item_id: record.id)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_audit_log
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chuck Smith
@@ -41,14 +41,20 @@ files:
41
41
  - app/controllers/rails_audit_log/application_controller.rb
42
42
  - app/helpers/rails_audit_log/application_helper.rb
43
43
  - app/jobs/rails_audit_log/application_job.rb
44
+ - app/jobs/rails_audit_log/write_audit_log_job.rb
44
45
  - app/models/rails_audit_log/application_record.rb
45
46
  - app/models/rails_audit_log/audit_log_entry.rb
46
47
  - app/views/layouts/rails_audit_log/application.html.erb
47
48
  - config/routes.rb
49
+ - lib/generators/rails_audit_log/initializer/initializer_generator.rb
50
+ - lib/generators/rails_audit_log/initializer/templates/rails_audit_log.rb
48
51
  - lib/generators/rails_audit_log/install/install_generator.rb
49
52
  - lib/generators/rails_audit_log/install/templates/create_audit_log_entries.rb
50
53
  - lib/rails_audit_log.rb
51
54
  - lib/rails_audit_log/engine.rb
55
+ - lib/rails_audit_log/matchers.rb
56
+ - lib/rails_audit_log/minitest_assertions.rb
57
+ - lib/rails_audit_log/test_helpers.rb
52
58
  - lib/rails_audit_log/version.rb
53
59
  - lib/tasks/rails_audit_log_tasks.rake
54
60
  homepage: https://github.com/eclectic-coding/rails_audit_log