rails_log_book 1.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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