attribute_guard 1.0.1 → 1.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 +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +11 -3
- data/VERSION +1 -1
- data/attribute_guard.gemspec +2 -2
- data/lib/attribute_guard.rb +26 -2
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fa71cf702b0f01ded796adf8ba3f215d024cf7a7947d633450213266df33cd74
|
4
|
+
data.tar.gz: 96bb1d220b952c302e9c749378be645c47fa66f49a0860d8b110ce49d2d1f0cb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 574fcacc35b3a9c4029999e6e9a8c89ae8d35c1f22e6187ebafbea27079e0f812a23bbf93fb42ccd667f570fa3060fba6f3bdc6e2fc1a3411bccb4066345710e
|
7
|
+
data.tar.gz: f3b1df97332fdfeed565332fb0be50a53811e95d3661ee0ca1988406ffe690e9cca734a2b6a136d4eacaddf2b995cf9d6c8eaa18d1647aa52ce39e6d96606c49
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## 1.1.0
|
8
|
+
|
9
|
+
### Added
|
10
|
+
|
11
|
+
- Added :raise mode that raises an error if a locked attribute has been changed instead of adding a validation error.
|
12
|
+
|
13
|
+
### Changed
|
14
|
+
|
15
|
+
- Changed gem dependency from `activerecord` to `activemodel`. You can now use locked attributes with ActiveModel classes that include `ActiveModel::Validations` and `ActiveModel::Dirty and implement a `new_record?` method.
|
16
|
+
|
7
17
|
## 1.0.1
|
8
18
|
|
9
19
|
### Added
|
data/README.md
CHANGED
@@ -3,8 +3,9 @@
|
|
3
3
|
[](https://github.com/bdurand/attribute_guard/actions/workflows/continuous_integration.yml)
|
4
4
|
[](https://github.com/bdurand/attribute_guard/actions/workflows/regression_test.yml)
|
5
5
|
[](https://github.com/testdouble/standard)
|
6
|
+
[](https://badge.fury.io/rb/attribute_guard)
|
6
7
|
|
7
|
-
This Ruby gem provides an extension for ActiveRecord allowing you to declare certain attributes in a model to be locked. Locked attributes cannot be changed once a record is created unless you explicitly allow changes.
|
8
|
+
This Ruby gem provides an extension for ActiveRecord/ActiveModel allowing you to declare certain attributes in a model to be locked. Locked attributes cannot be changed once a record is created unless you explicitly allow changes.
|
8
9
|
|
9
10
|
This feature can be used for a couple of different purposes.
|
10
11
|
|
@@ -118,7 +119,7 @@ record.update!(status: "canceled") # raises ActiveRecord::RecordInvalid error
|
|
118
119
|
|
119
120
|
### Modes
|
120
121
|
|
121
|
-
The default behavior when a locked attribute is changed is to add a validation error to the record. You can change this behavior with the `mode` option when locking attributes.
|
122
|
+
The default behavior when a locked attribute is changed is to add a validation error to the record. You can change this behavior with the `mode` option when locking attributes. You still need to validate the record to trigger the locked attribute check, regardless of the mode.
|
122
123
|
|
123
124
|
```ruby
|
124
125
|
class MyModel
|
@@ -126,16 +127,23 @@ class MyModel
|
|
126
127
|
|
127
128
|
lock_attributes :email, mode: :error
|
128
129
|
lock_attributes :name: mode: :warn
|
130
|
+
lock_attributes :updated_at, mode: :raise
|
129
131
|
lock_attributes :created_at, mode: ->(record, attribute) { raise "Created timestamp cannot be changed" }
|
130
132
|
end
|
131
133
|
```
|
132
134
|
|
133
135
|
* `:error` - Add a validation error to the record. This is the default.
|
134
136
|
|
135
|
-
* `:warn` - Log a warning that the record was changed. This mode is useful to allow you soft deploy locked attributes to production on a mature project and give you information about where you may need to update code to unlock attributes.
|
137
|
+
* `:warn` - Log a warning that the record was changed. This mode is useful to allow you soft deploy locked attributes to production on a mature project and give you information about where you may need to update code to unlock attributes. If the model does not have a `logger` method that returns a `Logger`-like object, then the output will be sent to `STDERR`.
|
138
|
+
|
139
|
+
* `:raise` = Raise an `AttributeGuard::LockedAttributeError` error.
|
136
140
|
|
137
141
|
* `Proc` - If you provide a `Proc` object, it will be called with the record and the attribute name when a locked attribute is changed.
|
138
142
|
|
143
|
+
### Using with ActiveModel
|
144
|
+
|
145
|
+
The gem works out of the box with ActiveRecord. You can also use it with ActiveModel classes as long as they include the `ActiveModel::Validations` and `ActiveModel::Dirty` modules. The model also needs to implement a `new_record?` method.
|
146
|
+
|
139
147
|
## Installation
|
140
148
|
|
141
149
|
Add this line to your application's Gemfile:
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0
|
1
|
+
1.1.0
|
data/attribute_guard.gemspec
CHANGED
@@ -4,7 +4,7 @@ Gem::Specification.new do |spec|
|
|
4
4
|
spec.authors = ["Brian Durand"]
|
5
5
|
spec.email = ["bbdurand@gmail.com"]
|
6
6
|
|
7
|
-
spec.summary = "ActiveRecord extension that allows locking attributes to prevent unintended updates."
|
7
|
+
spec.summary = "ActiveRecord/ActiveModel extension that allows locking attributes to prevent unintended updates."
|
8
8
|
|
9
9
|
spec.homepage = "https://github.com/bdurand/attribute_guard"
|
10
10
|
spec.license = "MIT"
|
@@ -31,7 +31,7 @@ Gem::Specification.new do |spec|
|
|
31
31
|
|
32
32
|
spec.required_ruby_version = ">= 2.5"
|
33
33
|
|
34
|
-
spec.add_dependency "
|
34
|
+
spec.add_dependency "activemodel", ">= 5.2"
|
35
35
|
|
36
36
|
spec.add_development_dependency "bundler"
|
37
37
|
end
|
data/lib/attribute_guard.rb
CHANGED
@@ -36,6 +36,9 @@ end
|
|
36
36
|
module AttributeGuard
|
37
37
|
extend ActiveSupport::Concern
|
38
38
|
|
39
|
+
class LockedAttributeError < StandardError
|
40
|
+
end
|
41
|
+
|
39
42
|
included do
|
40
43
|
class_attribute :locked_attributes, default: {}, instance_accessor: false
|
41
44
|
private_class_method :locked_attributes=
|
@@ -56,13 +59,19 @@ module AttributeGuard
|
|
56
59
|
# Validator that checks for changes to locked attributes.
|
57
60
|
class LockedAttributesValidator < ActiveModel::Validator
|
58
61
|
def validate(record)
|
62
|
+
unless record.respond_to?(:new_record?)
|
63
|
+
raise "AttributeGuard can only be used with models that respond to :new_record?"
|
64
|
+
end
|
65
|
+
|
59
66
|
return if record.new_record?
|
60
67
|
|
61
68
|
record.class.send(:locked_attributes).each do |attribute, params|
|
62
69
|
if record.changes.include?(attribute) && record.attribute_locked?(attribute)
|
63
70
|
message, mode = params
|
64
71
|
if mode == :warn
|
65
|
-
record
|
72
|
+
log_warning(record, attribute)
|
73
|
+
elsif mode == :raise
|
74
|
+
raise LockedAttributeError.new(error_message(record, attribute))
|
66
75
|
elsif mode.is_a?(Proc)
|
67
76
|
mode.call(record, attribute)
|
68
77
|
else
|
@@ -71,6 +80,21 @@ module AttributeGuard
|
|
71
80
|
end
|
72
81
|
end
|
73
82
|
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def error_message(record, attribute)
|
87
|
+
"Changed locked attribute #{attribute} on #{record.class.name} with id #{record.id}"
|
88
|
+
end
|
89
|
+
|
90
|
+
def log_warning(record, attribute)
|
91
|
+
message = error_message(record, attribute)
|
92
|
+
if record.respond_to?(:logger) && record.logger.respond_to?(:warn)
|
93
|
+
record.logger.warn(message)
|
94
|
+
else
|
95
|
+
warn(message)
|
96
|
+
end
|
97
|
+
end
|
74
98
|
end
|
75
99
|
|
76
100
|
module ClassMethods
|
@@ -113,7 +137,7 @@ module AttributeGuard
|
|
113
137
|
# user.unlock_attributes(:email).update!(email: "user@example.com")
|
114
138
|
#
|
115
139
|
# @param attributes [Array<Symbol, String>] the attributes to unlock
|
116
|
-
# @return [
|
140
|
+
# @return [Object] the object itself
|
117
141
|
def unlock_attributes(*attributes)
|
118
142
|
attributes = attributes.flatten.map(&:to_s)
|
119
143
|
return if attributes.empty?
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attribute_guard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Durand
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-04-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: activemodel
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '5.
|
19
|
+
version: '5.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '5.
|
26
|
+
version: '5.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -74,6 +74,6 @@ requirements: []
|
|
74
74
|
rubygems_version: 3.4.12
|
75
75
|
signing_key:
|
76
76
|
specification_version: 4
|
77
|
-
summary: ActiveRecord extension that allows locking attributes to prevent
|
78
|
-
updates.
|
77
|
+
summary: ActiveRecord/ActiveModel extension that allows locking attributes to prevent
|
78
|
+
unintended updates.
|
79
79
|
test_files: []
|