operator_recordable 1.1.0 → 1.3.1

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: 7a738b794ff45332a5df918bcec227d8c22683cefca6505b4127d53ca664ae78
4
- data.tar.gz: 2d895a62c309fc3b45d5b1dc8c9c31eeadf43e580e0fbea8ccb1b565beb50887
3
+ metadata.gz: 49732162b7408905bf8df338339f939127bc749d307fcf6639d52f173c645372
4
+ data.tar.gz: 1e2358023c22551afb02a430d5bb43c4f1908d867616f30e52754564cfb93b27
5
5
  SHA512:
6
- metadata.gz: df72ca9f3c177e9f237bd8af23bbb9ac03df004dfc46a4db268cae137a91a9a80cbcc04c564406d04cb3ae92e51c050ba92ca94d8ebf6ebb7be38e52b03ea4c3
7
- data.tar.gz: cb82594ea68b88414faf85d8ab556f6e58b44ee971b9886d1d34617c0618c290163761309b5e279fd8f4e589f8a7acca0397ef566215f391ea5697d0de94bf32
6
+ metadata.gz: 4453ea3b593441f2761abacdcf3407a9612adbe3d38758a3c6852c0a34b9147fb90d587aea8f95be986aa749611170d8547e5bbe4ab76ea05824a2cd80b11f93
7
+ data.tar.gz: f8833708e12cae1002924cb2d682936f0b5b43d10f65ee7fc4a92b1b2462ce0c1d01adb5431c57236c7064ddb38bf98a970232df3df181b5f97ec97454afed46
@@ -59,15 +59,6 @@ jobs:
59
59
  activerecord: '5.2'
60
60
  plugin: '_with_request_store'
61
61
  experimental: false
62
- # Rails 7.0.1 will start supporting Ruby 3.1, but Rails 7.0.1 has not been released yet
63
- - ruby: '3.1'
64
- activerecord: '7.0'
65
- plugin: ''
66
- experimental: false
67
- - ruby: '3.1'
68
- activerecord: '7.0'
69
- plugin: '_with_request_store'
70
- experimental: false
71
62
  include:
72
63
  - ruby: '2.7'
73
64
  activerecord: '5.2'
data/.rubocop.yml CHANGED
@@ -2,6 +2,7 @@ AllCops:
2
2
  Exclude:
3
3
  - gemfiles/**/*
4
4
  TargetRubyVersion: 2.5
5
+ NewCops: enable
5
6
 
6
7
  Style/AsciiComments:
7
8
  Enabled: false
@@ -23,6 +24,10 @@ Layout/EndOfLine:
23
24
  Layout/LineLength:
24
25
  Max: 128
25
26
 
27
+ Metrics/AbcSize:
28
+ Exclude:
29
+ - spec/**/*
30
+
26
31
  Metrics/BlockLength:
27
32
  Exclude:
28
33
  - spec/**/*
data/Appraisals CHANGED
@@ -32,12 +32,12 @@ appraise "activerecord_6.1_with_request_store" do
32
32
  end
33
33
 
34
34
  appraise "activerecord_7.0" do
35
- gem "activerecord", "~> 7.0.0"
35
+ gem "activerecord", "~> 7.0.1"
36
36
  gem "sqlite3", "~> 1.4"
37
37
  end
38
38
 
39
39
  appraise "activerecord_7.0_with_request_store" do
40
- gem "activerecord", "~> 7.0.0"
40
+ gem "activerecord", "~> 7.0.1"
41
41
  gem "request_store"
42
42
  gem "sqlite3", "~> 1.4"
43
43
  end
data/CHANGELOG.md CHANGED
@@ -1,20 +1,69 @@
1
1
  ## Unreleased
2
2
 
3
+
4
+ ## 1.3.1 (2022-06-20)
5
+
6
+ ### Bug fixes
7
+
8
+ * Fix recording discarded_by if the target table uses optimistic lock
9
+ + [PR#34](https://github.com/yujideveloper/operator_recordable/pull/34)
10
+
11
+
12
+ ## 1.3.0 (2022-06-01)
13
+
14
+ ### Changes
15
+
16
+ * Support discard gem for soft deletes
17
+ + [PR#31](https://github.com/yujideveloper/operator_recordable/pull/31)
18
+ * Get rid of needless guard clauses for ActiveSupport 5.1 and older
19
+ + [PR#32](https://github.com/yujideveloper/operator_recordable/pull/32)
20
+
21
+ ### Misc
22
+
23
+ * Fix RuboCop offenses
24
+ + [PR#33](https://github.com/yujideveloper/operator_recordable/pull/33)
25
+
26
+
27
+ ## 1.2.0 (2022-04-26)
28
+
29
+ ### Changes
30
+
31
+ * Make associations optional
32
+ + [PR#28](https://github.com/yujideveloper/operator_recordable/pull/28)
33
+
34
+ ### Misc
35
+
36
+ * CI against for Rails 7.0 running on Ruby 3.1
37
+ + [PR#26](https://github.com/yujideveloper/operator_recordable/pull/26)
38
+ * Call `super` in `OperatorRecordable::Recorder#initialize`
39
+ + [PR#30](https://github.com/yujideveloper/operator_recordable/pull/30)
40
+
41
+
3
42
  ## 1.1.0 (2022-01-07)
4
43
 
5
44
  ### Changes
6
45
 
7
46
  * Add gem metadata
47
+ + [PR#24](https://github.com/yujideveloper/operator_recordable/pull/24)
8
48
  * Drop Ruby 2.4 support
49
+ + [PR#25](https://github.com/yujideveloper/operator_recordable/pull/25)
9
50
  * Drop ActiveRecord 5.0 and 5.1 support
51
+ + [PR#25](https://github.com/yujideveloper/operator_recordable/pull/25)
10
52
 
11
53
  ### Misc
12
54
 
13
55
  * Introduce Appraisal
56
+ + [PR#19](https://github.com/yujideveloper/operator_recordable/pull/19)
14
57
  * CI against for ActiveRecord 6.1 and 7.0
58
+ + [PR#19](https://github.com/yujideveloper/operator_recordable/pull/19)
59
+ + [PR#22](https://github.com/yujideveloper/operator_recordable/pull/22)
15
60
  * Use GitHub Actions and stop using Travis CI
61
+ + [PR#20](https://github.com/yujideveloper/operator_recordable/pull/20)
16
62
  * CI against for Ruby 3.0 and 3.1
63
+ + [PR#23](https://github.com/yujideveloper/operator_recordable/pull/23)
64
+ + [PR#25](https://github.com/yujideveloper/operator_recordable/pull/25)
17
65
  * Require MFA to release gem
66
+ + [PR#24](https://github.com/yujideveloper/operator_recordable/pull/24)
18
67
 
19
68
 
20
69
  ## 1.0.0 (2020-10-16)
@@ -22,6 +71,7 @@
22
71
  ### Changes
23
72
 
24
73
  * Support Ruby 2.7
74
+ + [PR#14](https://github.com/yujideveloper/operator_recordable/pull/14)
25
75
 
26
76
 
27
77
  ## 0.4.0 (2019-08-22)
@@ -29,10 +79,12 @@
29
79
  ### Changes
30
80
 
31
81
  * Support ActiveRecord 6.0.0
82
+ + [PR#13](https://github.com/yujideveloper/operator_recordable/pull/13)
32
83
 
33
84
  ### Misc
34
85
 
35
86
  * Improve rspec and CI
87
+ + [PR#11](https://github.com/yujideveloper/operator_recordable/pull/11)
36
88
 
37
89
 
38
90
  ## 0.3.0 (2018-10-05)
@@ -40,6 +92,7 @@
40
92
  ### Breaking changes
41
93
 
42
94
  * Change mixin module from `OperatorRecordable` to `OperatorRecordable::Extension`
95
+ + [PR#5](https://github.com/yujideveloper/operator_recordable/pull/5)
43
96
 
44
97
 
45
98
  ## 0.2.0 (2018-09-27)
@@ -47,11 +100,14 @@
47
100
  ### Changes
48
101
 
49
102
  * Add association name options
103
+ + [PR#2](https://github.com/yujideveloper/operator_recordable/pull/2)
50
104
  * Modify not to define unnecessary class methods for ActiveRecord model
105
+ + [PR#3](https://github.com/yujideveloper/operator_recordable/pull/3)
51
106
 
52
107
  ### Misc
53
108
 
54
109
  * Remove unecessary `require`
110
+ + [PR#4](https://github.com/yujideveloper/operator_recordable/pull/4)
55
111
 
56
112
 
57
113
  ## 0.1.1 (2018-09-19)
@@ -59,6 +115,7 @@
59
115
  ### Misc
60
116
 
61
117
  * Refactor internal structures
118
+ + [PR#1](https://github.com/yujideveloper/operator_recordable/pull/1)
62
119
 
63
120
 
64
121
  ## 0.1.0 (2018-09-14)
data/README.md CHANGED
@@ -7,6 +7,8 @@
7
7
  OperatorRecordable is a Rails plugin gem that makes your ActiveRecord models to be saved or logically deleted with automatically set `created_by`, `updated_by`, and `deleted_by`.
8
8
  Also it makes `creator`, `updater`, and `deleter` `belongs_to` association if a class has `created_by`, `updated_by`, or `deleted_by`.
9
9
 
10
+ It also supports `discarded_by` column if [discard gem](https://github.com/jhawthorn/discard) is available.
11
+
10
12
  This gem is inspired by [RecordWithOperator](https://github.com/nay/record_with_operator).
11
13
 
12
14
  ## Installation
@@ -19,7 +21,7 @@ gem 'operator_recordable'
19
21
 
20
22
  And then execute:
21
23
 
22
- $ bundle
24
+ $ bundle install
23
25
 
24
26
  Or install it yourself as:
25
27
 
@@ -38,9 +40,11 @@ OperatorRecordable.config = {
38
40
  creator_column_name: "created_by",
39
41
  updater_column_name: "updated_by",
40
42
  deleter_column_name: "deleted_by",
43
+ discarder_column_name: "discarded_by",
41
44
  creator_association_name: "creator",
42
45
  updater_association_name: "updater",
43
46
  deleter_association_name: "deleter",
47
+ discarder_association_name: "discarder",
44
48
  operator_association_options: {},
45
49
  operator_association_scope: nil,
46
50
  store: :thread_store
@@ -55,10 +59,12 @@ OperatorRecordable.config = {
55
59
  | `creator_column_name` | String | column name of creator. | `"created_by"` |
56
60
  | `updater_column_name` | String | column name of updater. | `"updated_by"` |
57
61
  | `deleter_column_name` | String | column name of deleter. | `"deleted_by"` |
62
+ | `discarder_column_name` | String | column name of discarder. | `"discarded_by"` |
58
63
  | `creator_association_name` | String | association name of creator. | `"creator"` |
59
64
  | `updater_association_name` | String | association name of updater. | `"updater"` |
60
65
  | `deleter_association_name` | String | association name of deleter. | `"deleter"` |
61
- | `operator_association_options` | Hash | options of operator associations. e.g. `{ optional: true }` | `{}` |
66
+ | `discarder_association_name` | String | association name of discarder. | `"discarder"` |
67
+ | `operator_association_options` | Hash | options of operator associations. e.g. `{ touch: true }` | `{}` |
62
68
  | `operator_association_scope` | Proc | The scope of operator associations. e.g. `-> { with_deleted }` | `nil` |
63
69
  | `store` | Enum | operator store. any value of `:thread_store`, `:request_store` or `:current_attributes_store` | `:thread_store` |
64
70
 
@@ -99,7 +105,7 @@ This is default store.
99
105
  This store is implemented by using [RequestStore gem](https://github.com/steveklabnik/request_store).
100
106
  So, this requires RequestStore gem.
101
107
 
102
- RequestStore must be required before OperatorRecordable.
108
+ RequestStore must be loaded before OperatorRecordable.
103
109
 
104
110
  ``` ruby
105
111
  gem "request_store"
@@ -112,15 +118,14 @@ require "request_store"
112
118
  require "operator_recordable"
113
119
  ```
114
120
 
115
- Otherwise, you need to require it yourself.
121
+ Otherwise, you need to load it yourself.
116
122
  ``` ruby
117
123
  require "operator_recordable/store/request_store"
118
124
  ```
119
125
 
120
126
  #### `:current_attributes_store`
121
127
 
122
- This store is implemented by using [`ActiveSupport::CurrentAttributes`](https://api.rubyonrails.org/v5.2.0/classes/ActiveSupport/CurrentAttributes.html).
123
- So, this requires ActiveSupport 5.2 or later.
128
+ This store is implemented by using [`ActiveSupport::CurrentAttributes`](https://api.rubyonrails.org/v5.2.0/classes/ActiveSupport/CurrentAttributes.html).
124
129
 
125
130
 
126
131
  ## Development
@@ -2,7 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activerecord", "~> 7.0.0"
5
+ gem "activerecord", "~> 7.0.1"
6
6
  gem "sqlite3", "~> 1.4"
7
7
 
8
8
  gemspec path: "../"
@@ -2,7 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activerecord", "~> 7.0.0"
5
+ gem "activerecord", "~> 7.0.1"
6
6
  gem "request_store"
7
7
  gem "sqlite3", "~> 1.4"
8
8
 
@@ -11,8 +11,8 @@ module OperatorRecordable
11
11
  @store = initialize_store
12
12
  end
13
13
 
14
- %i[operator_class_name creator_column_name updater_column_name deleter_column_name
15
- creator_association_name updater_association_name deleter_association_name
14
+ %i[operator_class_name creator_column_name updater_column_name deleter_column_name discarder_column_name
15
+ creator_association_name updater_association_name deleter_association_name discarder_association_name
16
16
  operator_association_options operator_association_scope].each do |name|
17
17
  define_method name do
18
18
  config[name]
@@ -37,9 +37,11 @@ module OperatorRecordable
37
37
  creator_column_name: "created_by",
38
38
  updater_column_name: "updated_by",
39
39
  deleter_column_name: "deleted_by",
40
+ discarder_column_name: "discarded_by",
40
41
  creator_association_name: "creator",
41
42
  updater_association_name: "updater",
42
43
  deleter_association_name: "deleter",
44
+ discarder_association_name: "discarder",
43
45
  operator_association_options: {},
44
46
  operator_association_scope: nil,
45
47
  store: :thread_store
@@ -53,7 +55,7 @@ module OperatorRecordable
53
55
  end
54
56
 
55
57
  class Model
56
- VALID_ACTIONS = %i[create update destroy].freeze
58
+ VALID_ACTIONS = %i[create update destroy discard].freeze
57
59
 
58
60
  def initialize(actions)
59
61
  @actions = actions
@@ -72,6 +74,10 @@ module OperatorRecordable
72
74
  actions.include? :destroy
73
75
  end
74
76
 
77
+ def record_discarder?
78
+ actions.include? :discard
79
+ end
80
+
75
81
  private
76
82
 
77
83
  attr_reader :actions
@@ -5,6 +5,7 @@ require "operator_recordable/configuration"
5
5
  module OperatorRecordable
6
6
  class Recorder < ::Module
7
7
  def initialize(config)
8
+ super()
8
9
  define_activate_method(config)
9
10
  end
10
11
 
@@ -30,6 +31,11 @@ module OperatorRecordable
30
31
  m.__send__(:run_deleter_dsl, self, config)
31
32
  m.__send__(:define_deleter_instance_methods, self, config)
32
33
  end
34
+
35
+ if c.record_discarder?
36
+ m.__send__(:run_discarder_dsl, self, config)
37
+ m.__send__(:define_discarder_instance_methods, self, config)
38
+ end
33
39
  end
34
40
  end
35
41
 
@@ -48,46 +54,63 @@ module OperatorRecordable
48
54
  run_add_association_dsl(:deleter, klass, config)
49
55
  end
50
56
 
57
+ def run_discarder_dsl(klass, config)
58
+ klass.before_discard :"assign_#{config.discarder_association_name}"
59
+ run_add_association_dsl(:discarder, klass, config)
60
+ end
61
+
51
62
  def run_add_association_dsl(type, klass, config)
52
63
  klass.belongs_to config.association_name_for(type).to_sym,
53
64
  config.operator_association_scope,
54
65
  **{ foreign_key: config.column_name_for(type),
55
- class_name: config.operator_class_name }.merge(config.operator_association_options)
66
+ class_name: config.operator_class_name,
67
+ optional: true }.merge(config.operator_association_options)
56
68
  end
57
69
 
58
70
  def define_creator_instance_methods(klass, config)
59
71
  klass.class_eval <<~END_OF_DEF, __FILE__, __LINE__ + 1
60
- private def assign_#{config.creator_association_name}
61
- return unless (op = OperatorRecordable.operator)
62
-
63
- self.#{config.creator_column_name} = op.id
64
- end
72
+ private def assign_#{config.creator_association_name} # private def assign_creator
73
+ return unless (op = OperatorRecordable.operator) # return unless (op = OperatorRecordable.operator)
74
+ #
75
+ self.#{config.creator_column_name} = op.id # self.created_by = op.id
76
+ end # end
65
77
  END_OF_DEF
66
78
  end
67
79
 
68
80
  def define_updater_instance_methods(klass, config)
69
81
  klass.class_eval <<~END_OF_DEF, __FILE__, __LINE__ + 1
70
- private def assign_#{config.updater_association_name}
71
- return if !self.new_record? && !self.changed?
72
- return unless (op = OperatorRecordable.operator)
73
-
74
- self.#{config.updater_column_name} = op.id
75
- end
82
+ private def assign_#{config.updater_association_name} # private def assign_updater
83
+ return if !self.new_record? && !self.changed? # return if !self.new_record? && !self.changed?
84
+ return unless (op = OperatorRecordable.operator) # return unless (op = OperatorRecordable.operator)
85
+ #
86
+ self.#{config.updater_column_name} = op.id # self.updated_by = op.id
87
+ end # end
76
88
  END_OF_DEF
77
89
  end
78
90
 
79
91
  def define_deleter_instance_methods(klass, config)
80
92
  klass.class_eval <<~END_OF_DEF, __FILE__, __LINE__ + 1
81
- private def assign_#{config.deleter_association_name}
82
- return if self.frozen?
83
- return unless (op = OperatorRecordable.operator)
84
-
85
- self
86
- .class
87
- .where(self.class.primary_key => id)
88
- .update_all('#{config.deleter_column_name}' => op.id)
89
- self.#{config.deleter_column_name} = op.id
90
- end
93
+ private def assign_#{config.deleter_association_name} # private def assign_deleter
94
+ return if self.frozen? # return if self.frozen?
95
+ return unless (op = OperatorRecordable.operator) # return unless (op = OperatorRecordable.operator)
96
+ #
97
+ self # self
98
+ .class # .class
99
+ .where(self.class.primary_key => id) # .where(self.class.primary_key => id)
100
+ .update_all('#{config.deleter_column_name}' => op.id) # .update_all('deleted_by' => op.id)
101
+ self.#{config.deleter_column_name} = op.id # self.deleted_by = op.id
102
+ end # end
103
+ END_OF_DEF
104
+ end
105
+
106
+ def define_discarder_instance_methods(klass, config)
107
+ klass.class_eval <<~END_OF_DEF, __FILE__, __LINE__ + 1
108
+ private def assign_#{config.discarder_association_name} # private def assign_discarder
109
+ return if self.frozen? # return if self.frozen?
110
+ return unless (op = OperatorRecordable.operator) # return unless (op = OperatorRecordable.operator)
111
+ #
112
+ self.#{config.discarder_column_name} = op.id # self.discarded_by = op.id
113
+ end # end
91
114
  END_OF_DEF
92
115
  end
93
116
  end
@@ -15,4 +15,4 @@ end
15
15
 
16
16
  require "operator_recordable/store/thread_store"
17
17
  require "operator_recordable/store/request_store" if defined? ::RequestStore
18
- require "operator_recordable/store/current_attributes_store" if defined? ::ActiveSupport::CurrentAttributes
18
+ require "operator_recordable/store/current_attributes_store"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OperatorRecordable
4
- VERSION = "1.1.0"
4
+ VERSION = "1.3.1"
5
5
  end
@@ -34,7 +34,7 @@ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
34
34
 
35
35
  # Specify which files should be added to the gem when it is released.
36
36
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
37
- spec.files = Dir.chdir(__dir__) do
37
+ spec.files = Dir.chdir(__dir__) do
38
38
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
39
39
  end
40
40
  spec.bindir = "exe"
@@ -46,9 +46,10 @@ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
46
46
  spec.add_dependency "activerecord", ">= 5.2"
47
47
  spec.add_development_dependency "appraisal", ">= 2.3.0"
48
48
  spec.add_development_dependency "bundler", ">= 1.16"
49
+ spec.add_development_dependency "discard", ">= 1.2"
49
50
  spec.add_development_dependency "pry", ">= 0.10.0"
50
51
  spec.add_development_dependency "rake", ">= 10.0"
51
52
  spec.add_development_dependency "rspec", "~> 3.7"
52
- spec.add_development_dependency "rubocop", ">= 0.78.0"
53
+ spec.add_development_dependency "rubocop", ">= 1.13.0"
53
54
  spec.add_development_dependency "sqlite3", ">= 1.3.13"
54
55
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: operator_recordable
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuji Hanamura
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-01-06 00:00:00.000000000 Z
11
+ date: 2022-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.16'
55
+ - !ruby/object:Gem::Dependency
56
+ name: discard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '1.2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '1.2'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: pry
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -100,14 +114,14 @@ dependencies:
100
114
  requirements:
101
115
  - - ">="
102
116
  - !ruby/object:Gem::Version
103
- version: 0.78.0
117
+ version: 1.13.0
104
118
  type: :development
105
119
  prerelease: false
106
120
  version_requirements: !ruby/object:Gem::Requirement
107
121
  requirements:
108
122
  - - ">="
109
123
  - !ruby/object:Gem::Version
110
- version: 0.78.0
124
+ version: 1.13.0
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: sqlite3
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -171,7 +185,7 @@ metadata:
171
185
  source_code_uri: https://github.com/yujideveloper/operator_recordable
172
186
  changelog_uri: https://github.com/yujideveloper/operator_recordable/tree/master/CHANGELOG.md
173
187
  rubygems_mfa_required: 'true'
174
- post_install_message:
188
+ post_install_message:
175
189
  rdoc_options: []
176
190
  require_paths:
177
191
  - lib
@@ -186,8 +200,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
186
200
  - !ruby/object:Gem::Version
187
201
  version: '0'
188
202
  requirements: []
189
- rubygems_version: 3.2.21
190
- signing_key:
203
+ rubygems_version: 3.3.7
204
+ signing_key:
191
205
  specification_version: 4
192
206
  summary: OperatorRecordable is a Rails plugin to set created_by, updated_by, and deleted_by
193
207
  to ActiveRecord objects.