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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c1ad6773a9205c5481c708ac6685c0f0609018fb0bc03845b57db109a32bd6b3
4
- data.tar.gz: a4df65cd09d591fefb68fa9c3b1ccf311fbffcafb42e7ac7192622d747e05d49
3
+ metadata.gz: b6fdf694a84d42dbffbe36a1f6cb7e44f6743e7d6d0f107235a87390a66da4e5
4
+ data.tar.gz: a3e154ff527f732da68b229c33a342a7a28a578c9c694d4c8565d0c1d34bc72e
5
5
  SHA512:
6
- metadata.gz: f51346e32137f229013ccaf2f201e6d2ec2c60a806fb92f452818c1cf8d553a13f45744d17b0a0b8bff33496455611451443aa81f7f780826fa4b546fb91394e
7
- data.tar.gz: 4c7200f2d0dcbe341fda292fe71a916dd072c52a617c992c5140abb203765d4ce1b456efa67a20bf8ba3c310ea1038c90486424fce9b6e1844c91920c5910fbf
6
+ metadata.gz: 72cc3553913ba69636a5f9a0c64361aeefbceb0fad6933d273a67fadf5ddefec6cad09168bc6a17cbd04a4bb83af287ede6f4b7b894c7acb9facc1198697760b
7
+ data.tar.gz: 38a488f2626aea343a804696bb643976a0e2830bc39ee6036ba80d1cdb47454dad90435a3371d31fb8acf8d9a835b464b5fc956efa6d55f44056cdf6ca114469
@@ -12,12 +12,15 @@ jobs:
12
12
  strategy:
13
13
  fail-fast: false
14
14
  matrix:
15
- ruby: ['3.2', '3.3', '3.4']
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@v3
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.2', '3.3', '3.4']
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@v3
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 "⚠️ Rails head tests failed (non-blocking)"
88
+ echo "Rails head tests failed (non-blocking)"
86
89
  else
87
- echo "✅ Rails head tests passed"
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
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ArTransactionChanges
4
- VERSION = "1.1.11"
4
+ VERSION = "1.1.12"
5
5
  end
@@ -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
@@ -17,6 +17,8 @@ class User < ActiveRecord::Base
17
17
  serialize :notes, Array
18
18
  end
19
19
 
20
+ alias_attribute :job, :occupation
21
+
20
22
  attr_accessor :stored_transaction_changes
21
23
 
22
24
  after_commit :store_transaction_changes_for_tests
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.11
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: 3.6.9
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