rails_log_book 1.0.0 → 2.1.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: 33c84201892d61f332f7f60bd66ac9d052c37b9d9a894e5210eecf528efcb1ee
4
- data.tar.gz: 2dd8618869a1a1955e8c24261edbd11561662792d39e736de94513ea32b28358
3
+ metadata.gz: 1d058f0c867c6fce846e033d8aafa907e5dd4eff98faa8e26d7c7d92781af1ba
4
+ data.tar.gz: a7e97c3ca16861c470646e534b11055c8a849d27838de24f39d4ee93e6ac0412
5
5
  SHA512:
6
- metadata.gz: 1f0b026c941e50454283953976c11eef81cba06e8c37ddb6ffaffbfb1ca1c3ef030c1b6e82c5be68c9151948465fa335ae4f3b79a8e2606a4a0190559e6f07cd
7
- data.tar.gz: 0b321da7a85b6fe8620fe1863ac26560c3dd40a5fa06eabf1a7d4d1ec0f299d296994634370bac9c66a82990440ae2d578ced623b617474d2f864ec8b6443bde
6
+ metadata.gz: 4181481765b293567c425908b00f9c0518bf69993ccf728016ad997c2f4dbc3434acd9ea852184bc3eadf98d90ba64996c21c20bb7da0755c517e722ce607d40
7
+ data.tar.gz: ab44200dda93ed92505d3b218bd656b6877ea8e289d56608ffc99cfcd9d7338945c59bc43c552c1e71a2e32664666ec6d02aa7062176fcb38a67624d811d93ac
data/.gitignore CHANGED
@@ -8,4 +8,4 @@
8
8
  /spec/reports/
9
9
  /tmp/
10
10
 
11
- spec/rails_app/log
11
+ spec/rails_app/log/*
data/.reek.yml ADDED
@@ -0,0 +1,25 @@
1
+ detectors:
2
+ IrresponsibleModule:
3
+ enabled: false
4
+ directories:
5
+ "app/controllers":
6
+ IrresponsibleModule:
7
+ enabled: false
8
+ NestedIterators:
9
+ max_allowed_nesting: 2
10
+ UnusedPrivateMethod:
11
+ enabled: false
12
+ InstanceVariableAssumption:
13
+ enabled: false
14
+ "app/helpers":
15
+ IrresponsibleModule:
16
+ enabled: false
17
+ UtilityFunction:
18
+ enabled: false
19
+ "app/mailers":
20
+ InstanceVariableAssumption:
21
+ enabled: false
22
+ "app/models":
23
+ InstanceVariableAssumption:
24
+ enabled: false
25
+
data/.rubocop.yml ADDED
@@ -0,0 +1,35 @@
1
+ require: rubocop-rspec
2
+
3
+ LineLength:
4
+ Max: 100
5
+
6
+ Documentation:
7
+ Enabled: false
8
+
9
+ FrozenStringLiteralComment:
10
+ Enabled: false
11
+
12
+ WordArray:
13
+ Enabled: false
14
+
15
+ SymbolArray:
16
+ Enabled: false
17
+
18
+ Rails:
19
+ Enabled: true
20
+
21
+ RSpec/ExampleLength:
22
+ Max: 10
23
+
24
+ Style/MutableConstant:
25
+ Enabled: false
26
+
27
+ Metrics/BlockLength:
28
+ Exclude:
29
+ - 'spec/**/*_spec.rb'
30
+
31
+ AllCops:
32
+ Exclude:
33
+ - 'db/schema.rb'
34
+ - 'db/migrate/*.rb'
35
+ - 'config/**/*.rb'
data/README.md CHANGED
@@ -21,6 +21,15 @@ Then run:
21
21
  rails generate log_book:install
22
22
  rake db:migrate
23
23
  ```
24
+ ## Reasoning
25
+
26
+ We built this gem because others did not offer us what we needed.
27
+
28
+ Benefits:
29
+ - new features ([Squashing](#squashing))
30
+ - Explicit (needs to be told when to record, as opposed to paper_trail or audited which always record; ie. do not record stuff done in console)
31
+ - Has an inbuilt caching mechanism with `meta` field
32
+ - ``meta`` field can also be used to add aditional keys on which search queries can be run
24
33
 
25
34
  ## Usage
26
35
 
@@ -44,6 +53,73 @@ Add to controlers and actions you want the tracker to be active:
44
53
 
45
54
  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
55
 
56
+ ## Squashing
57
+
58
+ The idea of squashing came when we needed to show an activity page where you have a has_many relation setup but you need to show changes only on the "main" object.
59
+
60
+ Example:
61
+
62
+ ```ruby
63
+ class Hotel < ApplicationRecord
64
+ include LogBook::Recorder
65
+ has_log_book_records
66
+
67
+ has_many :amenities
68
+ accepts_nested_attributes_for :amenities
69
+ end
70
+
71
+ class HotelAmenity < ApplicationRecord
72
+ include LogBook::Recorder
73
+ has_log_book_records, parent: :hotel
74
+
75
+ belongs_to :hotel
76
+ belongs_to :amenity
77
+ end
78
+
79
+ class Amenity < ApplicationRecord
80
+ has_many :hotels
81
+ end
82
+
83
+ class HotelsController < ApplicationController
84
+ def create
85
+ @hotel = Hotel.create(hotel_params)
86
+ end
87
+
88
+ def hotel_params
89
+ params.require(:hotel).permit(amenities_attributes: [:id, :status])
90
+ end
91
+ end
92
+
93
+ # having this params passed to hotels_controller:
94
+ { name: 'Hotel', amenitites_attributes: { 0: {id: 1, status: :avaliable}, 1: { id: 4, status: :unavaliable } } }
95
+
96
+ # Without squashing you would have these records in the DB (abbreviated for clairity)
97
+ [
98
+ {subject_type: 'Hotel', subject_id: 1, parent_type: nil, parent_id: nil, record_changes: { name: [nil, 'Hotel']}},
99
+ {subject_type: 'HotelAmenity', subject_id: 1, parent_type: 'Hotel', parent_id: 1, record_changes: { name: [nil, 'avaliable']}},
100
+ {subject_type: 'HotelAmenity', subject_id: 4, parent_type: 'Hotel', parent_id: 1, record_changes: { name: [nil, 'unavaliable']}},
101
+ ]
102
+
103
+ # The above is rather difficult to paginate if you want to show changes done on HotelAmenities to show under Hotel.
104
+ # With squashing enabled:
105
+ [
106
+ {
107
+ subject_type: 'Hotel',
108
+ subject_id: 1,
109
+ parent_type: nil,
110
+ parent_id: nil,
111
+ record_changes: {
112
+ name: [nil, 'Hotel'],
113
+ hotel_amenitites: {
114
+ 1: {status: [nil, 'avaliable']},
115
+ 2: {status: [nil, 'unavaliable']}
116
+ }
117
+ }
118
+ }
119
+ ]
120
+
121
+ ```
122
+
47
123
  ## ActiveRecord Options
48
124
 
49
125
  ### fields
@@ -82,7 +158,7 @@ By default, whenever a user record is created, updated or deleted in any actions
82
158
 
83
159
  ### parent
84
160
 
85
- Define who is a parent of this object. Will be recorded in a `parent` polymorphic columns
161
+ Define who is a parent of this object.
86
162
 
87
163
  ``` ruby
88
164
  class User < ActiveRecord::Base
@@ -94,6 +170,31 @@ Define who is a parent of this object. Will be recorded in a `parent` polymorphi
94
170
  end
95
171
  ```
96
172
 
173
+ ### parent_of
174
+
175
+ Define who this object is a parent of.
176
+
177
+ ``` ruby
178
+ class Account < ActiveRecord::Base
179
+ include LogBook::Recorder
180
+ has_many :user_memberships
181
+ has_many :users, through: :user_memberships
182
+ end
183
+
184
+ def UserMembership < ActiveRecord::Base
185
+ belongs_to :account
186
+ belongs_to :user
187
+ end
188
+
189
+ class User < ActiveRecord::Base
190
+ has_one :user_membership
191
+ has_one :account, through: :user_membership
192
+
193
+ # Parent is Company and will be recorded with each user change
194
+ # has_log_book_records parent_of: :account
195
+ end
196
+ ```
197
+
97
198
  ### meta
98
199
 
99
200
  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
@@ -113,18 +214,6 @@ Arbitrary column. This is a jsonb field which can have all kinds of information.
113
214
  end
114
215
  ```
115
216
 
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
217
  ## ActionController options
129
218
 
130
219
  ### current\_author
@@ -159,27 +248,15 @@ end
159
248
 
160
249
  ``` ruby
161
250
  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
251
+ LogBook.author=(author ) #=> Records as a different author within block
252
+ LogBook.action=(value) #=> Change default action for this request
164
253
  LogBook.with_record_squashing {} #=> Squashes records within block
165
254
  LogBook.enable_recording #=> Enables recording from this point
166
255
  LogBook.disable_recording #=> Disables recording from this point
167
256
  LogBook.record_squashing_enabled #=> Enables record squashing from this point
168
257
  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
258
  ```
172
259
 
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
- ```
183
260
  ## Development
184
261
 
185
262
  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.
data/bin/console CHANGED
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require "bundler/setup"
4
- require "log_book"
4
+ require "rails"
5
+ require "rails_log_book"
5
6
 
6
7
  # You can add fixtures and/or initialization code here to make experimenting
7
8
  # with your gem easier. You can also use a different console, if you like.
@@ -1,28 +1,10 @@
1
1
  module LogBook
2
- def self.configure
3
- @configuration ||= Configuration.new
4
- yield(@configuration)
5
- end
2
+ extend Dry::Configurable
6
3
 
7
- def self.config
8
- @configuration ||= Configuration.new
9
- end
10
-
11
- class Configuration
12
- attr_accessor :records_table_name
13
- attr_accessor :ignored_attributes
14
- attr_accessor :recording_enabled
15
- attr_accessor :author_method
16
- attr_accessor :record_squashing
17
- attr_accessor :skip_if_empty_actions
18
-
19
- def initialize
20
- @records_table_name = 'records'
21
- @ignored_attributes = [:updated_at, :created_at]
22
- @author_method = :current_user
23
- @record_squashing = false
24
- @recording_enabled = false
25
- @skip_if_empty_actions = [:update]
26
- end
27
- end
4
+ setting :records_table_name, 'records'
5
+ setting :ignored_attributes, [:updated_at, :created_at]
6
+ setting :recording_enabled, false
7
+ setting :author_method, :current_user
8
+ setting :record_squashing, false
9
+ setting :skip_if_empty_actions, [:update]
28
10
  end
@@ -4,24 +4,24 @@ module LogBook
4
4
 
5
5
  included do
6
6
  before_action :enable_recording
7
- around_action :record_squashing
7
+ after_action :save_records
8
8
  end
9
9
 
10
10
  def enable_recording
11
- LogBook.store[:controller] = self
12
- LogBook.store[:author] = current_author
13
- LogBook.store[:request_uuid] = try(:request).try(:uuid) || SecureRandom.hex
11
+ action = "#{controller_name}##{action_name}"
12
+ author = current_author
13
+ request_uuid = try(:request).try(:uuid) || SecureRandom.hex
14
+ LogBook::Store.tree = LogBook::Tree.new(action: action, author: author, request_uuid: request_uuid)
14
15
  LogBook.enable_recording
15
16
  end
16
17
 
17
- def record_squashing
18
- LogBook.with_record_squashing do
19
- yield
20
- end
18
+ def save_records
19
+ LogBook::SaveRecords.call
21
20
  end
22
21
 
23
22
  def current_author
24
23
  raise NotImplementedError unless respond_to?(LogBook.config.author_method, true)
24
+
25
25
  send(LogBook.config.author_method)
26
26
  end
27
27
  end
@@ -5,29 +5,5 @@ module LogBook
5
5
  belongs_to :subject, polymorphic: true
6
6
  belongs_to :author, polymorphic: true
7
7
  belongs_to :parent, polymorphic: true
8
-
9
- before_create :set_request_uuid
10
-
11
- def self.collection_cache_key(collection = all, timestamp_column = :created_at)
12
- super(collection, timestamp_column)
13
- end
14
-
15
- def subject_key
16
- subject.class.table_name
17
- end
18
-
19
- def changes_to_record?
20
- !(record_changes == {} && skip_if_empty_actions.include?(action))
21
- end
22
-
23
- private
24
-
25
- def set_request_uuid
26
- self.request_uuid ||= LogBook.store[:request_uuid] || SecureRandom.uuid
27
- end
28
-
29
- def skip_if_empty_actions
30
- (subject.recording_options[:skip_if_empty_actions] || LogBook.config.skip_if_empty_actions).map(&:to_s)
31
- end
32
8
  end
33
9
  end
@@ -12,9 +12,9 @@ module LogBook
12
12
  scope :with_records, -> { joins(:records) }
13
13
 
14
14
  on = Array.wrap(options[:on])
15
- after_create :create_record if on.empty? || on.include?(:create)
16
- after_update :update_record if on.empty? || on.include?(:update)
17
- after_destroy :destroy_record if on.empty? || on.include?(:destroy)
15
+ after_create :store_changes if on.empty? || on.include?(:create)
16
+ after_update :store_changes if on.empty? || on.include?(:update)
17
+ after_destroy :store_changes if on.empty? || on.include?(:destroy)
18
18
 
19
19
  extend LogBook::Recorder::RecordingClassMethods
20
20
  include LogBook::Recorder::RecordingInstanceMethods
@@ -22,8 +22,12 @@ module LogBook
22
22
  end
23
23
 
24
24
  module RecordingInstanceMethods
25
- def to_squash?
26
- recording_options[:squash]
25
+ def recording_changes
26
+ @recording_changes ||= RecordingChanges.new(self)
27
+ end
28
+
29
+ def recording_options
30
+ self.class.recording_options
27
31
  end
28
32
 
29
33
  def save_with_recording
@@ -42,6 +46,10 @@ module LogBook
42
46
  self.class.non_recording_columns
43
47
  end
44
48
 
49
+ def recording_key
50
+ "#{self.class.table_name}_#{id}"
51
+ end
52
+
45
53
  private
46
54
 
47
55
  def record_changes
@@ -53,43 +61,23 @@ module LogBook
53
61
  end
54
62
  end
55
63
 
56
- def create_record
57
- write_record(:create)
58
- end
59
-
60
- def update_record
61
- write_record(:update)
62
- end
63
-
64
- def destroy_record
65
- write_record(:destroy)
66
- end
67
-
68
- def write_record(action)
64
+ def store_changes
69
65
  return unless LogBook.recording_enabled
70
- record = new_record(LogBook.store[:action] || action)
71
- return unless record.changes_to_record?
72
- record.save
73
- end
74
66
 
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
67
+ recording_changes.tap do |record|
68
+ record.record_changes = record_changes
69
+ record.meta = log_book_meta_info(record) if recording_options[:meta].present?
70
+ end
71
+
72
+ LogBook::Store.tree.add(recording_changes)
86
73
  end
87
74
 
88
75
  def log_book_meta_info(record)
89
- case recording_options[:meta]
76
+ meta_options = recording_options[:meta]
77
+ case meta_options
90
78
  when NilClass then nil
91
- when Symbol then send(recording_options[:meta], record)
92
- when Proc then recording_options[:meta].call(self, record)
79
+ when Symbol then send(meta_options, record)
80
+ when Proc then meta_options.call(self, record)
93
81
  when TrueClass then log_book_meta(record)
94
82
  end
95
83
  end
@@ -121,5 +109,58 @@ module LogBook
121
109
  [primary_key, inheritance_column, *Array.wrap(LogBook.config.ignored_attributes)]
122
110
  end
123
111
  end
112
+
113
+ class RecordingChanges
114
+ attr_reader :subject
115
+ attr_reader :action
116
+ attr_reader :author
117
+ attr_reader :record_changes
118
+ attr_reader :meta
119
+ attr_reader :request_uuid
120
+ attr_accessor :recording_key
121
+
122
+ def initialize(recorder)
123
+ @subject = recorder
124
+ @recording_key = subject.recording_key
125
+ @record_changes = {}
126
+ @meta = {}
127
+ end
128
+
129
+ def record_changes=(value)
130
+ @record_changes.merge!(value)
131
+ end
132
+
133
+ def meta=(value)
134
+ @meta.merge!(value)
135
+ end
136
+
137
+ def changes?
138
+ meta.present? || record_changes.present?
139
+ end
140
+
141
+ def subject_key
142
+ subject.class.table_name
143
+ end
144
+
145
+ def subject_id
146
+ subject.id
147
+ end
148
+
149
+ def parent
150
+ self.class.new(subject.send(subject.recording_options[:parent])) if subject.recording_options[:parent]
151
+ end
152
+
153
+ def children
154
+ self.class.new(subject.send(subject.recording_options[:parent_of])) if subject.recording_options[:parent_of]
155
+ end
156
+
157
+ def to_h
158
+ {
159
+ subject: subject,
160
+ record_changes: record_changes,
161
+ meta: meta
162
+ }
163
+ end
164
+ end
124
165
  end
125
166
  end
@@ -0,0 +1,56 @@
1
+ module LogBook
2
+ class SaveRecords
3
+ def initialize
4
+ @tree = LogBook::Store.tree
5
+ end
6
+
7
+ def self.call
8
+ new.call
9
+ end
10
+
11
+ def call
12
+ return unless LogBook.recording_enabled
13
+
14
+ squash_tree(tree) if LogBook.record_squashing_enabled
15
+
16
+ tree.records(only_roots: LogBook.record_squashing_enabled).each do |_key, record|
17
+ create_record(record.value)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :tree
24
+
25
+ def squash_tree(tree)
26
+ tree.depth.downto(1).each do |depth|
27
+ nodes = tree.at_depth(depth)
28
+ nodes.each do |_, node|
29
+ next unless node.value.changes?
30
+ parent = node.parent.value
31
+
32
+ parent.record_changes = squashed_changes(node.value, parent.record_changes, :record_changes)
33
+ parent.meta = squashed_changes(node.value, parent.meta, :meta)
34
+ end
35
+ end
36
+ end
37
+
38
+ def squashed_changes(record, object, key)
39
+ object[record.subject_key] ||= {}
40
+ object[record.subject_key][record.subject_id] = record.send(key)
41
+ object
42
+ end
43
+
44
+ def create_record(record)
45
+ return unless record.changes?
46
+
47
+ attributes = record.to_h
48
+ attributes.merge!(
49
+ author: tree.author,
50
+ action: tree.action,
51
+ request_uuid: tree.request_uuid
52
+ )
53
+ LogBook::Record.create(attributes)
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,12 @@
1
+ module LogBook
2
+ class Store < ActiveSupport::CurrentAttributes
3
+ # attribute :author
4
+ # attribute :action
5
+ # attribute :controller
6
+ # attribute :request_uuid
7
+ attribute :recording_enabled
8
+ attribute :record_squashing
9
+
10
+ attribute :tree
11
+ end
12
+ end
@@ -0,0 +1,74 @@
1
+ module LogBook
2
+ class Tree
3
+ attr_accessor :author, :action, :request_uuid, :nodes, :depth
4
+
5
+ def initialize(author: nil, action: nil, request_uuid: nil)
6
+ @nodes = {}
7
+ @depth = 0
8
+ @author = author
9
+ @action = action
10
+ @request_uuid = request_uuid
11
+ end
12
+
13
+ def add(record)
14
+ node = nodes[record.recording_key] ||= Node.new(record)
15
+ add_parent(node, record.parent)
16
+ add_children(node, record.children)
17
+ end
18
+
19
+ def add_parent(node, parent)
20
+ return unless parent
21
+
22
+ parent_node = nodes[parent.recording_key] ||= Node.new(parent)
23
+ node.parent = parent_node
24
+ parent_node.children << node
25
+ update_depth(parent_node, parent_node.depth)
26
+ end
27
+
28
+ def add_children(node, children)
29
+ return unless children
30
+
31
+ Array.wrap(children).each do |child|
32
+ add_child(node, child)
33
+ end
34
+ end
35
+
36
+ def add_child(node, child)
37
+ return unless child
38
+
39
+ child_node = nodes[child.recording_key] ||= Node.new(child)
40
+ child_node.parent = node
41
+ node.children << child_node
42
+ update_depth(node, node.depth)
43
+ end
44
+
45
+ def update_depth(node, depth)
46
+ node.depth = depth
47
+ @depth = [@depth, depth].max
48
+ node.children.each do |child|
49
+ update_depth(child, depth + 1)
50
+ end
51
+ end
52
+
53
+ def records(only_roots: false)
54
+ only_roots ? at_depth(0) : nodes
55
+ end
56
+
57
+ def at_depth(depth)
58
+ nodes.select { |_, node| node.depth == depth}
59
+ end
60
+
61
+ class Node
62
+ attr_reader :value
63
+ attr_accessor :parent
64
+ attr_accessor :children
65
+ attr_accessor :depth
66
+
67
+ def initialize(value)
68
+ @value = value
69
+ @depth = 0
70
+ @children = []
71
+ end
72
+ end
73
+ end
74
+ end
@@ -1,3 +1,3 @@
1
1
  module LogBook
2
- VERSION = '1.0.0'
2
+ VERSION = '2.1.0'
3
3
  end
@@ -1,7 +1,11 @@
1
1
  require 'active_record'
2
- require 'request_store'
2
+ require 'active_support/current_attributes'
3
+ require 'dry-configurable'
4
+
3
5
  require 'log_book/configuration'
4
- require 'log_book/squash_records'
6
+ require 'log_book/store'
7
+ require 'log_book/tree'
8
+ require 'log_book/save_records'
5
9
  require 'log_book/record'
6
10
  require 'log_book/recorder'
7
11
  require 'log_book/controller_record'
@@ -10,64 +14,40 @@ require 'log_book/railtie'
10
14
 
11
15
  module LogBook
12
16
  class << self
13
- def store
14
- RequestStore.store[:log_book] ||= {}
15
- end
16
-
17
17
  def with_recording
18
18
  recording_was_disabled = recording_enabled
19
19
  enable_recording
20
- yield
21
- ensure
22
- disable_recording unless recording_was_disabled
23
- end
20
+ LogBook::Store.tree = LogBook::Tree.new
24
21
 
25
- def without_recording
26
- recording_was_enabled = recording_enabled
27
- disable_recording
28
22
  yield
29
- ensure
30
- enable_recording unless recording_was_enabled
31
- end
32
23
 
33
- def record_as(author)
34
- prev_author = LogBook.store[:author]
35
- LogBook.store[:author] = author
36
- yield
24
+ LogBook::SaveRecords.call
37
25
  ensure
38
- LogBook.store[:author] = prev_author
39
- end
40
-
41
- def with_record_squashing
42
- yield
43
- squash_records if record_squashing_enabled
26
+ disable_recording unless recording_was_disabled
44
27
  end
45
28
 
46
29
  def recording_enabled
47
- LogBook.store.fetch(:recording_enabled, false)
30
+ LogBook::Store.recording_enabled || LogBook.config.recording_enabled
48
31
  end
49
32
 
50
33
  def record_squashing_enabled
51
- LogBook.store.fetch(:record_squashing, LogBook.config.record_squashing)
34
+ LogBook::Store.record_squashing || LogBook.config.record_squashing
52
35
  end
53
36
 
54
37
  def disable_recording
55
- LogBook.recording_enabled = false
38
+ LogBook::Store.recording_enabled = false
56
39
  end
57
40
 
58
41
  def enable_recording
59
- LogBook.recording_enabled = true
42
+ LogBook::Store.recording_enabled = true
60
43
  end
61
44
 
62
- def recording_enabled=(val)
63
- LogBook.store[:recording_enabled] = val
45
+ def action=(val)
46
+ LogBook::Store.tree.action = val
64
47
  end
65
48
 
66
- def squash_records
67
- return if LogBook.store[:request_uuid].nil?
68
- records = LogBook::Record.where(request_uuid: LogBook.store[:request_uuid])
69
- return unless records.exists?
70
- LogBook::SquashRecords.new(records).call
49
+ def author=(val)
50
+ LogBook::Store.tree.author = val
71
51
  end
72
52
  end
73
53
  end
data/log_book.gemspec CHANGED
@@ -1,4 +1,4 @@
1
- lib = File.expand_path('../lib', __FILE__)
1
+ lib = File.expand_path('lib', __dir__)
2
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
  require 'log_book/version'
4
4
 
@@ -25,12 +25,14 @@ Gem::Specification.new do |spec|
25
25
  spec.require_paths = ['lib']
26
26
 
27
27
  spec.add_development_dependency 'bundler', '~> 1.12'
28
- spec.add_development_dependency 'rake', '~> 10.0'
29
- spec.add_development_dependency 'rspec-rails'
30
- spec.add_development_dependency 'rails'
28
+ spec.add_development_dependency 'factory_bot'
31
29
  spec.add_development_dependency 'pg'
32
30
  spec.add_development_dependency 'pry-byebug'
31
+ spec.add_development_dependency 'rails'
32
+ spec.add_development_dependency 'rake', '~> 10.0'
33
+ spec.add_development_dependency 'rspec-rails'
33
34
 
34
- spec.add_dependency 'request_store'
35
35
  spec.add_dependency 'activerecord', '> 5.2'
36
+ spec.add_dependency 'activesupport', '> 5.2'
37
+ spec.add_dependency 'dry-configurable'
36
38
  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: 1.0.0
4
+ version: 2.1.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: 2018-09-06 00:00:00.000000000 Z
11
+ date: 2019-06-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -25,21 +25,21 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.12'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rake
28
+ name: factory_bot
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rspec-rails
42
+ name: pg
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rails
56
+ name: pry-byebug
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: pg
70
+ name: rails
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -81,27 +81,27 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: pry-byebug
84
+ name: rake
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: '10.0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ">="
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0'
96
+ version: '10.0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: request_store
98
+ name: rspec-rails
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
102
102
  - !ruby/object:Gem::Version
103
103
  version: '0'
104
- type: :runtime
104
+ type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
@@ -122,6 +122,34 @@ dependencies:
122
122
  - - ">"
123
123
  - !ruby/object:Gem::Version
124
124
  version: '5.2'
125
+ - !ruby/object:Gem::Dependency
126
+ name: activesupport
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">"
130
+ - !ruby/object:Gem::Version
131
+ version: '5.2'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">"
137
+ - !ruby/object:Gem::Version
138
+ version: '5.2'
139
+ - !ruby/object:Gem::Dependency
140
+ name: dry-configurable
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
125
153
  description: Write a longer description or delete this line.
126
154
  email:
127
155
  - stjepan.hadjic@infinum.co
@@ -130,7 +158,9 @@ extensions: []
130
158
  extra_rdoc_files: []
131
159
  files:
132
160
  - ".gitignore"
161
+ - ".reek.yml"
133
162
  - ".rspec"
163
+ - ".rubocop.yml"
134
164
  - ".travis.yml"
135
165
  - CODE_OF_CONDUCT.md
136
166
  - Gemfile
@@ -148,7 +178,9 @@ files:
148
178
  - lib/log_book/railtie.rb
149
179
  - lib/log_book/record.rb
150
180
  - lib/log_book/recorder.rb
151
- - lib/log_book/squash_records.rb
181
+ - lib/log_book/save_records.rb
182
+ - lib/log_book/store.rb
183
+ - lib/log_book/tree.rb
152
184
  - lib/log_book/version.rb
153
185
  - lib/rails_log_book.rb
154
186
  - lib/tasks/log_book.rake
@@ -174,7 +206,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
174
206
  version: '0'
175
207
  requirements: []
176
208
  rubyforge_project:
177
- rubygems_version: 2.7.3
209
+ rubygems_version: 2.7.6
178
210
  signing_key:
179
211
  specification_version: 4
180
212
  summary: Write a short summary, because Rubygems requires one.
@@ -1,50 +0,0 @@
1
- module LogBook
2
- class SquashRecords
3
- def initialize(records)
4
- @records = records
5
- end
6
-
7
- def call
8
- records.group_by(&:parent).each do |parent, children|
9
- children_to_squash = children.select { |child| child.subject.try(:to_squash?) }
10
- next if children_to_squash.empty?
11
-
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
-
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
31
- end
32
- end
33
-
34
- private
35
-
36
- attr_reader :records
37
-
38
- def squashed_changes(children, key)
39
- children.each_with_object({}) do |record, object|
40
- object[record.subject_key] ||= {}
41
- object[record.subject_key][record.subject_id] = record.send(key)
42
- end
43
- end
44
-
45
- def parent_in_records(parent)
46
- records.find { |record| record.subject == parent } ||
47
- parent.new_record
48
- end
49
- end
50
- end