ar_transaction_changes 1.1.11 → 1.1.12
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/.github/workflows/ci.yml +9 -6
- data/README.md +5 -0
- data/ar_transaction_changes.gemspec +1 -0
- data/lib/ar_transaction_changes/version.rb +1 -1
- data/lib/ar_transaction_changes.rb +57 -0
- data/test/models/account.rb +13 -0
- data/test/models/plan_change.rb +16 -0
- data/test/models/user.rb +2 -0
- data/test/test_helper.rb +5 -0
- data/test/transaction_changes_test.rb +37 -0
- metadata +8 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b6fdf694a84d42dbffbe36a1f6cb7e44f6743e7d6d0f107235a87390a66da4e5
|
|
4
|
+
data.tar.gz: a3e154ff527f732da68b229c33a342a7a28a578c9c694d4c8565d0c1d34bc72e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 72cc3553913ba69636a5f9a0c64361aeefbceb0fad6933d273a67fadf5ddefec6cad09168bc6a17cbd04a4bb83af287ede6f4b7b894c7acb9facc1198697760b
|
|
7
|
+
data.tar.gz: 38a488f2626aea343a804696bb643976a0e2830bc39ee6036ba80d1cdb47454dad90435a3371d31fb8acf8d9a835b464b5fc956efa6d55f44056cdf6ca114469
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -12,12 +12,15 @@ jobs:
|
|
|
12
12
|
strategy:
|
|
13
13
|
fail-fast: false
|
|
14
14
|
matrix:
|
|
15
|
-
|
|
15
|
+
# Cover maintained Ruby branches, including security-only maintenance.
|
|
16
|
+
ruby: ['3.3', '3.4', '4.0']
|
|
16
17
|
rails: ['7.0', '7.1', '7.2', '8.0']
|
|
17
18
|
exclude:
|
|
18
19
|
# Rails 7.0 requires Ruby < 3.4
|
|
19
20
|
- ruby: '3.4'
|
|
20
21
|
rails: '7.0'
|
|
22
|
+
- ruby: '4.0'
|
|
23
|
+
rails: '7.0'
|
|
21
24
|
|
|
22
25
|
name: Ruby ${{ matrix.ruby }} / Rails ${{ matrix.rails }}
|
|
23
26
|
|
|
@@ -29,7 +32,7 @@ jobs:
|
|
|
29
32
|
run: |
|
|
30
33
|
sudo apt-get update
|
|
31
34
|
sudo apt-get -y install libsqlite3-dev
|
|
32
|
-
- uses: actions/checkout@
|
|
35
|
+
- uses: actions/checkout@v7
|
|
33
36
|
- name: Set up Ruby
|
|
34
37
|
uses: ruby/setup-ruby@v1
|
|
35
38
|
with:
|
|
@@ -45,7 +48,7 @@ jobs:
|
|
|
45
48
|
strategy:
|
|
46
49
|
fail-fast: false
|
|
47
50
|
matrix:
|
|
48
|
-
ruby: ['3.
|
|
51
|
+
ruby: ['3.3', '3.4', '4.0']
|
|
49
52
|
|
|
50
53
|
name: Ruby ${{ matrix.ruby }} / Rails head
|
|
51
54
|
|
|
@@ -57,7 +60,7 @@ jobs:
|
|
|
57
60
|
run: |
|
|
58
61
|
sudo apt-get update
|
|
59
62
|
sudo apt-get -y install libsqlite3-dev
|
|
60
|
-
- uses: actions/checkout@
|
|
63
|
+
- uses: actions/checkout@v7
|
|
61
64
|
- name: Set up Ruby
|
|
62
65
|
uses: ruby/setup-ruby@v1
|
|
63
66
|
with:
|
|
@@ -82,7 +85,7 @@ jobs:
|
|
|
82
85
|
fi
|
|
83
86
|
echo "✅ All required tests passed"
|
|
84
87
|
if [ "${{ needs.test-head.result }}" != "success" ]; then
|
|
85
|
-
echo "
|
|
88
|
+
echo "Rails head tests failed (non-blocking)"
|
|
86
89
|
else
|
|
87
|
-
echo "
|
|
90
|
+
echo "Rails head tests passed"
|
|
88
91
|
fi
|
data/README.md
CHANGED
|
@@ -64,3 +64,8 @@ gem 'globalize', require: ['ar_transaction_changes', 'globalize']
|
|
|
64
64
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
65
65
|
4. Push to the branch (`git push origin my-new-feature`)
|
|
66
66
|
5. Create new Pull Request
|
|
67
|
+
|
|
68
|
+
## Releasing
|
|
69
|
+
|
|
70
|
+
Publishing is restricted to [RubyGems.org](https://rubygems.org) through the
|
|
71
|
+
`allowed_push_host` gem metadata.
|
|
@@ -12,6 +12,7 @@ Gem::Specification.new do |gem|
|
|
|
12
12
|
gem.summary = %q{Store transaction changes for active record objects}
|
|
13
13
|
gem.homepage = "https://github.com/Shopify/ar_transaction_changes"
|
|
14
14
|
gem.license = "MIT"
|
|
15
|
+
gem.metadata["allowed_push_host"] = "https://rubygems.org"
|
|
15
16
|
|
|
16
17
|
gem.required_ruby_version = ">= 3.2"
|
|
17
18
|
|
|
@@ -4,6 +4,56 @@ require "ar_transaction_changes/version"
|
|
|
4
4
|
require "active_record"
|
|
5
5
|
|
|
6
6
|
module ArTransactionChanges
|
|
7
|
+
# Since rails/rails#59191, generated attribute writers (`name=`) call
|
|
8
|
+
# `@attributes.write_from_user` directly instead of `_write_attribute`, so the
|
|
9
|
+
# `_write_attribute` override below no longer sees them. Generate writers that
|
|
10
|
+
# record the change around that same direct write.
|
|
11
|
+
module GeneratedWriters # :nodoc:
|
|
12
|
+
# Rails versions with that change also dropped the `owner` argument from
|
|
13
|
+
# `AttrNames.define_attribute_accessor_method`, which the code below relies on.
|
|
14
|
+
def self.needed?
|
|
15
|
+
ActiveModel::AttributeMethods::AttrNames
|
|
16
|
+
.method(:define_attribute_accessor_method)
|
|
17
|
+
.parameters.none? { |_type, name| name == :owner }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.raise_on_assign_to_attr_readonly?
|
|
21
|
+
if ActiveRecord.respond_to?(:_raise_on_assign_to_attr_readonly)
|
|
22
|
+
ActiveRecord._raise_on_assign_to_attr_readonly
|
|
23
|
+
else
|
|
24
|
+
ActiveRecord.raise_on_assign_to_attr_readonly
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def define_method_attribute=(canonical_name, owner:, as: canonical_name)
|
|
31
|
+
return super unless self < ArTransactionChanges
|
|
32
|
+
|
|
33
|
+
readonly = GeneratedWriters.raise_on_assign_to_attr_readonly? && readonly_attribute?(canonical_name)
|
|
34
|
+
|
|
35
|
+
ActiveModel::AttributeMethods::AttrNames.define_attribute_accessor_method(
|
|
36
|
+
canonical_name, writer: true,
|
|
37
|
+
) do |temp_method_name, attr_name_expr|
|
|
38
|
+
namespace = readonly ? :ar_transaction_changes_readonly : :ar_transaction_changes
|
|
39
|
+
owner.define_cached_method(temp_method_name, as: "#{as}=", namespace: namespace) do |batch|
|
|
40
|
+
batch << "def #{temp_method_name}(value)"
|
|
41
|
+
if readonly
|
|
42
|
+
batch <<
|
|
43
|
+
" unless new_record?" <<
|
|
44
|
+
" raise ActiveRecord::ReadonlyAttributeError.new(#{attr_name_expr})" <<
|
|
45
|
+
" end"
|
|
46
|
+
end
|
|
47
|
+
batch <<
|
|
48
|
+
" _store_transaction_changed_attributes(#{attr_name_expr}) do" <<
|
|
49
|
+
" @attributes.write_from_user(#{attr_name_expr}, value)" <<
|
|
50
|
+
" end" <<
|
|
51
|
+
"end"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
7
57
|
if ActiveRecord.version >= Gem::Version.new('7.1')
|
|
8
58
|
def run_callbacks(kind, type = nil)
|
|
9
59
|
super
|
|
@@ -113,3 +163,10 @@ module ArTransactionChanges
|
|
|
113
163
|
end
|
|
114
164
|
end
|
|
115
165
|
end
|
|
166
|
+
|
|
167
|
+
# Install on ActiveRecord::Base rather than from an `included` hook, so models that get
|
|
168
|
+
# ArTransactionChanges through a concern are covered too. The writers are generated on
|
|
169
|
+
# first use, after the model's modules are included.
|
|
170
|
+
ActiveSupport.on_load(:active_record) do
|
|
171
|
+
singleton_class.prepend(ArTransactionChanges::GeneratedWriters) if ArTransactionChanges::GeneratedWriters.needed?
|
|
172
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class Account < ActiveRecord::Base
|
|
2
|
+
include ArTransactionChanges
|
|
3
|
+
|
|
4
|
+
attr_readonly :handle
|
|
5
|
+
|
|
6
|
+
attr_accessor :stored_transaction_changes
|
|
7
|
+
|
|
8
|
+
after_commit :store_transaction_changes_for_tests
|
|
9
|
+
|
|
10
|
+
def store_transaction_changes_for_tests
|
|
11
|
+
@stored_transaction_changes = transaction_changed_attributes.to_h
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module TracksTransactionChanges
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
include ArTransactionChanges
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
attr_accessor :stored_transaction_changes
|
|
7
|
+
|
|
8
|
+
after_commit { @stored_transaction_changes = transaction_changed_attributes.to_h }
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class PlanChange < ActiveRecord::Base
|
|
13
|
+
self.table_name = "accounts"
|
|
14
|
+
|
|
15
|
+
include TracksTransactionChanges
|
|
16
|
+
end
|
data/test/models/user.rb
CHANGED
data/test/test_helper.rb
CHANGED
|
@@ -25,6 +25,11 @@ ActiveRecord::Base.connection.tap do |db|
|
|
|
25
25
|
t.text :notes
|
|
26
26
|
t.timestamps null: false
|
|
27
27
|
end
|
|
28
|
+
|
|
29
|
+
db.create_table(:accounts) do |t|
|
|
30
|
+
t.string :handle
|
|
31
|
+
t.string :plan
|
|
32
|
+
end
|
|
28
33
|
end
|
|
29
34
|
|
|
30
35
|
Dir[test_dir.join("models/*.rb")].each{ |file| require file }
|
|
@@ -23,6 +23,43 @@ class TransactionChangesTest < Minitest::Test
|
|
|
23
23
|
assert_equal ["Dylan", "Dillon"], @user.stored_transaction_changes["name"]
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
+
def test_transaction_changes_for_aliased_attribute_writer
|
|
27
|
+
@user.job = "Tester"
|
|
28
|
+
@user.save!
|
|
29
|
+
|
|
30
|
+
assert_equal ["Developer", "Tester"], @user.stored_transaction_changes["occupation"]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def test_readonly_attribute_writer_still_raises_on_persisted_records
|
|
34
|
+
account = Account.create!(handle: "dylan", plan: "basic")
|
|
35
|
+
assert_equal({ "handle" => nil, "plan" => nil }, account.stored_transaction_changes.slice("handle", "plan"))
|
|
36
|
+
|
|
37
|
+
raises = if ActiveRecord.respond_to?(:_raise_on_assign_to_attr_readonly)
|
|
38
|
+
ActiveRecord._raise_on_assign_to_attr_readonly
|
|
39
|
+
elsif ActiveRecord.respond_to?(:raise_on_assign_to_attr_readonly)
|
|
40
|
+
ActiveRecord.raise_on_assign_to_attr_readonly
|
|
41
|
+
end
|
|
42
|
+
if raises
|
|
43
|
+
assert_raises(ActiveRecord::ReadonlyAttributeError) { account.handle = "dillon" }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
account.plan = "pro"
|
|
47
|
+
account.save!
|
|
48
|
+
assert_equal({ "plan" => "basic" }, account.stored_transaction_changes)
|
|
49
|
+
ensure
|
|
50
|
+
Account.delete_all
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def test_transaction_changes_when_included_through_a_concern
|
|
54
|
+
record = PlanChange.create!(handle: "dylan", plan: "basic")
|
|
55
|
+
record.plan = "pro"
|
|
56
|
+
record.save!
|
|
57
|
+
|
|
58
|
+
assert_equal({ "plan" => "basic" }, record.stored_transaction_changes)
|
|
59
|
+
ensure
|
|
60
|
+
PlanChange.delete_all
|
|
61
|
+
end
|
|
62
|
+
|
|
26
63
|
def test_transaction_changes_for_updating_attribute
|
|
27
64
|
@user[:name] = "Dillon"
|
|
28
65
|
@user.save!
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ar_transaction_changes
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.12
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dylan Thacker-Smith
|
|
@@ -64,13 +64,16 @@ files:
|
|
|
64
64
|
- lib/ar_transaction_changes.rb
|
|
65
65
|
- lib/ar_transaction_changes/version.rb
|
|
66
66
|
- test/database.yml.default
|
|
67
|
+
- test/models/account.rb
|
|
68
|
+
- test/models/plan_change.rb
|
|
67
69
|
- test/models/user.rb
|
|
68
70
|
- test/test_helper.rb
|
|
69
71
|
- test/transaction_changes_test.rb
|
|
70
72
|
homepage: https://github.com/Shopify/ar_transaction_changes
|
|
71
73
|
licenses:
|
|
72
74
|
- MIT
|
|
73
|
-
metadata:
|
|
75
|
+
metadata:
|
|
76
|
+
allowed_push_host: https://rubygems.org
|
|
74
77
|
rdoc_options: []
|
|
75
78
|
require_paths:
|
|
76
79
|
- lib
|
|
@@ -85,11 +88,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
85
88
|
- !ruby/object:Gem::Version
|
|
86
89
|
version: '0'
|
|
87
90
|
requirements: []
|
|
88
|
-
rubygems_version:
|
|
91
|
+
rubygems_version: 4.0.23
|
|
89
92
|
specification_version: 4
|
|
90
93
|
summary: Store transaction changes for active record objects
|
|
91
94
|
test_files:
|
|
92
95
|
- test/database.yml.default
|
|
96
|
+
- test/models/account.rb
|
|
97
|
+
- test/models/plan_change.rb
|
|
93
98
|
- test/models/user.rb
|
|
94
99
|
- test/test_helper.rb
|
|
95
100
|
- test/transaction_changes_test.rb
|