├── .github └── workflows │ └── actions.yml ├── .gitignore ├── Gemfile ├── Gemfile.lock ├── Rakefile ├── Readme.md ├── ar_after_transaction.gemspec ├── gemfiles ├── rails6.1.gemfile ├── rails6.1.gemfile.lock ├── rails7.0.gemfile ├── rails7.0.gemfile.lock ├── rails7.1.gemfile ├── rails7.1.gemfile.lock ├── rails7.2.gemfile ├── rails7.2.gemfile.lock ├── rails8.0.gemfile └── rails8.0.gemfile.lock ├── lib ├── ar_after_transaction.rb └── ar_after_transaction │ └── version.rb └── spec ├── after_initialize_spec.rb ├── ar_after_transaction_spec.rb ├── setup_database.rb └── spec_helper.rb /.github/workflows/actions.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: [master] 5 | pull_request: 6 | branches: [master] 7 | jobs: 8 | build: 9 | name: ruby${{ matrix.ruby }} rails${{ matrix.rails }} rake 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | ruby: ['3.1', '3.2', '3.3'] 14 | rails: ['6.1', '7.0', '7.1', '7.2', '8.0'] 15 | exclude: 16 | - ruby: '3.1' 17 | rails: '8.0' 18 | env: 19 | BUNDLE_GEMFILE: gemfiles/rails${{ matrix.rails }}.gemfile 20 | steps: 21 | - uses: actions/checkout@v2 22 | - uses: ruby/setup-ruby@v1 23 | with: 24 | ruby-version: ${{ matrix.ruby }} 25 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically 26 | - run: bundle exec rake 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle 2 | .ruby-version 3 | /gemfiles/.bundle 4 | /log 5 | /vendor/bundle 6 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | gemspec 6 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | ar_after_transaction (0.13.0) 5 | activerecord (>= 6.1.0, < 8.1) 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | actioncable (7.2.0) 11 | actionpack (= 7.2.0) 12 | activesupport (= 7.2.0) 13 | nio4r (~> 2.0) 14 | websocket-driver (>= 0.6.1) 15 | zeitwerk (~> 2.6) 16 | actionmailbox (7.2.0) 17 | actionpack (= 7.2.0) 18 | activejob (= 7.2.0) 19 | activerecord (= 7.2.0) 20 | activestorage (= 7.2.0) 21 | activesupport (= 7.2.0) 22 | mail (>= 2.8.0) 23 | actionmailer (7.2.0) 24 | actionpack (= 7.2.0) 25 | actionview (= 7.2.0) 26 | activejob (= 7.2.0) 27 | activesupport (= 7.2.0) 28 | mail (>= 2.8.0) 29 | rails-dom-testing (~> 2.2) 30 | actionpack (7.2.0) 31 | actionview (= 7.2.0) 32 | activesupport (= 7.2.0) 33 | nokogiri (>= 1.8.5) 34 | racc 35 | rack (>= 2.2.4, < 3.2) 36 | rack-session (>= 1.0.1) 37 | rack-test (>= 0.6.3) 38 | rails-dom-testing (~> 2.2) 39 | rails-html-sanitizer (~> 1.6) 40 | useragent (~> 0.16) 41 | actiontext (7.2.0) 42 | actionpack (= 7.2.0) 43 | activerecord (= 7.2.0) 44 | activestorage (= 7.2.0) 45 | activesupport (= 7.2.0) 46 | globalid (>= 0.6.0) 47 | nokogiri (>= 1.8.5) 48 | actionview (7.2.0) 49 | activesupport (= 7.2.0) 50 | builder (~> 3.1) 51 | erubi (~> 1.11) 52 | rails-dom-testing (~> 2.2) 53 | rails-html-sanitizer (~> 1.6) 54 | activejob (7.2.0) 55 | activesupport (= 7.2.0) 56 | globalid (>= 0.3.6) 57 | activemodel (7.2.0) 58 | activesupport (= 7.2.0) 59 | activerecord (7.2.0) 60 | activemodel (= 7.2.0) 61 | activesupport (= 7.2.0) 62 | timeout (>= 0.4.0) 63 | activestorage (7.2.0) 64 | actionpack (= 7.2.0) 65 | activejob (= 7.2.0) 66 | activerecord (= 7.2.0) 67 | activesupport (= 7.2.0) 68 | marcel (~> 1.0) 69 | activesupport (7.2.0) 70 | base64 71 | bigdecimal 72 | concurrent-ruby (~> 1.0, >= 1.3.1) 73 | connection_pool (>= 2.2.5) 74 | drb 75 | i18n (>= 1.6, < 2) 76 | logger (>= 1.4.2) 77 | minitest (>= 5.1) 78 | securerandom (>= 0.3) 79 | tzinfo (~> 2.0, >= 2.0.5) 80 | base64 (0.2.0) 81 | bigdecimal (3.1.8) 82 | builder (3.3.0) 83 | bump (0.10.0) 84 | concurrent-ruby (1.3.4) 85 | connection_pool (2.4.1) 86 | crass (1.0.6) 87 | date (3.3.4) 88 | diff-lcs (1.5.1) 89 | drb (2.2.1) 90 | erubi (1.13.0) 91 | globalid (1.2.1) 92 | activesupport (>= 6.1) 93 | i18n (1.14.5) 94 | concurrent-ruby (~> 1.0) 95 | io-console (0.7.2) 96 | irb (1.14.0) 97 | rdoc (>= 4.0.0) 98 | reline (>= 0.4.2) 99 | logger (1.6.0) 100 | loofah (2.22.0) 101 | crass (~> 1.0.2) 102 | nokogiri (>= 1.12.0) 103 | mail (2.8.1) 104 | mini_mime (>= 0.1.1) 105 | net-imap 106 | net-pop 107 | net-smtp 108 | marcel (1.0.4) 109 | mini_mime (1.1.5) 110 | minitest (5.25.1) 111 | net-imap (0.4.14) 112 | date 113 | net-protocol 114 | net-pop (0.1.2) 115 | net-protocol 116 | net-protocol (0.2.2) 117 | timeout 118 | net-smtp (0.5.0) 119 | net-protocol 120 | nio4r (2.7.3) 121 | nokogiri (1.16.7-aarch64-linux) 122 | racc (~> 1.4) 123 | nokogiri (1.16.7-arm-linux) 124 | racc (~> 1.4) 125 | nokogiri (1.16.7-arm64-darwin) 126 | racc (~> 1.4) 127 | nokogiri (1.16.7-x86-linux) 128 | racc (~> 1.4) 129 | nokogiri (1.16.7-x86_64-darwin) 130 | racc (~> 1.4) 131 | nokogiri (1.16.7-x86_64-linux) 132 | racc (~> 1.4) 133 | psych (5.1.2) 134 | stringio 135 | racc (1.8.1) 136 | rack (3.1.7) 137 | rack-session (2.0.0) 138 | rack (>= 3.0.0) 139 | rack-test (2.1.0) 140 | rack (>= 1.3) 141 | rackup (2.1.0) 142 | rack (>= 3) 143 | webrick (~> 1.8) 144 | rails (7.2.0) 145 | actioncable (= 7.2.0) 146 | actionmailbox (= 7.2.0) 147 | actionmailer (= 7.2.0) 148 | actionpack (= 7.2.0) 149 | actiontext (= 7.2.0) 150 | actionview (= 7.2.0) 151 | activejob (= 7.2.0) 152 | activemodel (= 7.2.0) 153 | activerecord (= 7.2.0) 154 | activestorage (= 7.2.0) 155 | activesupport (= 7.2.0) 156 | bundler (>= 1.15.0) 157 | railties (= 7.2.0) 158 | rails-dom-testing (2.2.0) 159 | activesupport (>= 5.0.0) 160 | minitest 161 | nokogiri (>= 1.6) 162 | rails-html-sanitizer (1.6.0) 163 | loofah (~> 2.21) 164 | nokogiri (~> 1.14) 165 | railties (7.2.0) 166 | actionpack (= 7.2.0) 167 | activesupport (= 7.2.0) 168 | irb (~> 1.13) 169 | rackup (>= 1.0.0) 170 | rake (>= 12.2) 171 | thor (~> 1.0, >= 1.2.2) 172 | zeitwerk (~> 2.6) 173 | rake (13.2.1) 174 | rdoc (6.7.0) 175 | psych (>= 4.0.0) 176 | reline (0.5.9) 177 | io-console (~> 0.5) 178 | rspec (3.13.0) 179 | rspec-core (~> 3.13.0) 180 | rspec-expectations (~> 3.13.0) 181 | rspec-mocks (~> 3.13.0) 182 | rspec-core (3.13.0) 183 | rspec-support (~> 3.13.0) 184 | rspec-expectations (3.13.1) 185 | diff-lcs (>= 1.2.0, < 2.0) 186 | rspec-support (~> 3.13.0) 187 | rspec-mocks (3.13.1) 188 | diff-lcs (>= 1.2.0, < 2.0) 189 | rspec-support (~> 3.13.0) 190 | rspec-support (3.13.1) 191 | securerandom (0.3.1) 192 | sqlite3 (1.7.3-aarch64-linux) 193 | sqlite3 (1.7.3-arm-linux) 194 | sqlite3 (1.7.3-arm64-darwin) 195 | sqlite3 (1.7.3-x86-linux) 196 | sqlite3 (1.7.3-x86_64-darwin) 197 | sqlite3 (1.7.3-x86_64-linux) 198 | stringio (3.1.1) 199 | thor (1.3.1) 200 | timeout (0.4.1) 201 | tzinfo (2.0.6) 202 | concurrent-ruby (~> 1.0) 203 | useragent (0.16.10) 204 | webrick (1.8.1) 205 | websocket-driver (0.7.6) 206 | websocket-extensions (>= 0.1.0) 207 | websocket-extensions (0.1.5) 208 | wwtd (1.4.1) 209 | zeitwerk (2.6.17) 210 | 211 | PLATFORMS 212 | aarch64-linux 213 | arm-linux 214 | arm64-darwin 215 | x86-linux 216 | x86_64-darwin 217 | x86_64-linux 218 | 219 | DEPENDENCIES 220 | ar_after_transaction! 221 | bump 222 | rails 223 | rake 224 | rspec (~> 3) 225 | sqlite3 (~> 1.0) 226 | wwtd 227 | 228 | BUNDLED WITH 229 | 2.5.14 230 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'bundler/setup' 4 | require 'bundler/gem_tasks' 5 | require 'bump/tasks' 6 | Bump.replace_in_default = Dir["gemfiles/*.lock"] 7 | 8 | task default: :spec 9 | task :spec do 10 | sh 'rspec spec' 11 | end 12 | 13 | desc 'Bundle all gemfiles CMD=install' 14 | task :bundle_all do 15 | Bundler.with_original_env do 16 | Dir['gemfiles/*.gemfile'].each do |gemfile| 17 | sh "BUNDLE_GEMFILE=#{gemfile} bundle #{ENV["CMD"]}" 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | [![Gem Version](https://badge.fury.io/rb/ar_after_transaction.png)](http://badge.fury.io/rb/ar_after_transaction) 2 | ![CI](https://github.com/grosser/ar_after_transaction/workflows/CI/badge.svg) 3 | 4 | Do something only after the currently open transactions have finished. 5 | 6 | Normally everything gets rolled back when a transaction fails, but you cannot roll back sending an email or adding a job to Resque. 7 | 8 | Install 9 | ======= 10 | 11 | ```bash 12 | gem install ar_after_transaction 13 | ``` 14 | 15 | 16 | Usage 17 | ===== 18 | 19 | ### just-in-time callbacks 20 | 21 | ```ruby 22 | class User 23 | after_create :do_stuff, :oops 24 | 25 | def do_stuff 26 | after_transaction do 27 | send_an_email # cannot be rolled back 28 | end 29 | comments.create(...) # will be rolled back 30 | end 31 | 32 | def oops 33 | raise "do the rolback!" 34 | end 35 | end 36 | ``` 37 | 38 | ### General 'this should be rolled back when in a transaction' code like jobs 39 | 40 | ```ruby 41 | class Resque 42 | def revertable_enqueue(*args) 43 | ActiveRecord::Base.after_transaction do 44 | enqueue(*args) 45 | end 46 | end 47 | end 48 | ``` 49 | 50 | ### When not in a transaction 51 | after_transaction will perform the given block immediately 52 | 53 | ### Transactional fixtures <-> normally_open_transactions 54 | after_transaction assumes zero open transactions.
55 | If you use transactional fixtures you should change it in test mode. 56 | 57 | `Rspec:` 58 | ```ruby 59 | # spec/rails_helper.rb 60 | config.before(:suite) do 61 | ActiveRecord::Base.normally_open_transactions = 1 62 | end 63 | ``` 64 | 65 | ### Adding new rails versions 66 | 67 | - bump in `ar_after_transaction.gemspec` 68 | - create a new gemfiles/.gemfile 69 | - `BUNDLE_GEMFILE=gemfiles/.gemfile bundle` 70 | - `BUNDLE_GEMFILE=gemfiles/.gemfile bundle exec rake` 71 | - update `.github/workflows/actions.yml` 72 | - make a PR 73 | 74 | Alternative 75 | =========== 76 | 77 | Rails 3+ 78 | - basic support is built in, use it if you can! 79 | - `after_commit :foo` 80 | - `after_commit :bar, on: :create / :update` 81 | - [after_commit everywhere](https://dev.to/evilmartians/rails-aftercommit-everywhere--4j9g) 82 | 83 | 84 | [after_commit](https://github.com/pat/after_commit)
85 | - pro: threadsafe
86 | - pro: more fine-grained callbacks (before_commit, `after_commit`, before_rollback, after_rollback)
87 | - con: doesn't let you define `after_transaction` callbacks *anywhere* like `ar_after_transaction` does (*outside* of the `after_commit`, etc. callbacks which only happen at certain points in the model's life cycle)
88 | - con: more complex
89 | 90 | Authors 91 | ======= 92 | [Original idea and code](https://rails.lighthouseapp.com/projects/8994/tickets/2991-after-transaction-patch) from [Jamis Buck](http://weblog.jamisbuck.org/) (post by Jeremy Kemper) 93 | 94 | ### [Contributors](http://github.com/grosser/ar_after_transaction/contributors) 95 | - [Bogdan Gusiev](http://gusiev.com) 96 | - [Benedikt Deicke](http://blog.synatic.net) 97 | - [Tyler Rick](https://github.com/TylerRick) 98 | - [Michael Wu](https://github.com/michaelmwu) 99 | - [C.W.](https://github.com/compwron) 100 | - [Ben Weintraub](https://github.com/benweint) 101 | - [Vladimir Temnikov](https://github.com/vladimirtemnikov) 102 | - [Mark Gangl](https://github.com/attack) 103 | - [Alex Vondrak](https://github.com/ajvondrak) 104 | 105 | [Michael Grosser](http://grosser.it)
106 | michael@grosser.it
107 | License: MIT
108 | -------------------------------------------------------------------------------- /ar_after_transaction.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require './lib/ar_after_transaction/version' 4 | 5 | Gem::Specification.new 'ar_after_transaction', ARAfterTransaction::VERSION do |s| 6 | s.summary = 'Execute irreversible actions only when transactions are not rolled back' 7 | s.authors = ['Michael Grosser'] 8 | s.email = 'michael@grosser.it' 9 | s.homepage = 'http://github.com/grosser/ar_after_transaction' 10 | s.files = `git ls-files lib Readme.md`.split("\n") 11 | s.required_ruby_version = '>= 3.1.0' 12 | s.add_runtime_dependency 'activerecord', '>= 6.1.0', '< 8.1' 13 | s.add_development_dependency 'bump' 14 | s.add_development_dependency 'rails' 15 | s.add_development_dependency 'rake' 16 | s.add_development_dependency 'rspec', '~> 3' 17 | s.add_development_dependency 'sqlite3', '~> 1.0' # avoid 2.0 for now 18 | s.add_development_dependency 'wwtd' 19 | s.license = 'MIT' 20 | end 21 | -------------------------------------------------------------------------------- /gemfiles/rails6.1.gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | gem 'activerecord', '~>6.1.0' 6 | 7 | gemspec path: '../' 8 | -------------------------------------------------------------------------------- /gemfiles/rails6.1.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .. 3 | specs: 4 | ar_after_transaction (0.13.0) 5 | activerecord (>= 6.1.0, < 8.1) 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | actioncable (6.1.4.4) 11 | actionpack (= 6.1.4.4) 12 | activesupport (= 6.1.4.4) 13 | nio4r (~> 2.0) 14 | websocket-driver (>= 0.6.1) 15 | actionmailbox (6.1.4.4) 16 | actionpack (= 6.1.4.4) 17 | activejob (= 6.1.4.4) 18 | activerecord (= 6.1.4.4) 19 | activestorage (= 6.1.4.4) 20 | activesupport (= 6.1.4.4) 21 | mail (>= 2.7.1) 22 | actionmailer (6.1.4.4) 23 | actionpack (= 6.1.4.4) 24 | actionview (= 6.1.4.4) 25 | activejob (= 6.1.4.4) 26 | activesupport (= 6.1.4.4) 27 | mail (~> 2.5, >= 2.5.4) 28 | rails-dom-testing (~> 2.0) 29 | actionpack (6.1.4.4) 30 | actionview (= 6.1.4.4) 31 | activesupport (= 6.1.4.4) 32 | rack (~> 2.0, >= 2.0.9) 33 | rack-test (>= 0.6.3) 34 | rails-dom-testing (~> 2.0) 35 | rails-html-sanitizer (~> 1.0, >= 1.2.0) 36 | actiontext (6.1.4.4) 37 | actionpack (= 6.1.4.4) 38 | activerecord (= 6.1.4.4) 39 | activestorage (= 6.1.4.4) 40 | activesupport (= 6.1.4.4) 41 | nokogiri (>= 1.8.5) 42 | actionview (6.1.4.4) 43 | activesupport (= 6.1.4.4) 44 | builder (~> 3.1) 45 | erubi (~> 1.4) 46 | rails-dom-testing (~> 2.0) 47 | rails-html-sanitizer (~> 1.1, >= 1.2.0) 48 | activejob (6.1.4.4) 49 | activesupport (= 6.1.4.4) 50 | globalid (>= 0.3.6) 51 | activemodel (6.1.4.4) 52 | activesupport (= 6.1.4.4) 53 | activerecord (6.1.4.4) 54 | activemodel (= 6.1.4.4) 55 | activesupport (= 6.1.4.4) 56 | activestorage (6.1.4.4) 57 | actionpack (= 6.1.4.4) 58 | activejob (= 6.1.4.4) 59 | activerecord (= 6.1.4.4) 60 | activesupport (= 6.1.4.4) 61 | marcel (~> 1.0.0) 62 | mini_mime (>= 1.1.0) 63 | activesupport (6.1.4.4) 64 | concurrent-ruby (~> 1.0, >= 1.0.2) 65 | i18n (>= 1.6, < 2) 66 | minitest (>= 5.1) 67 | tzinfo (~> 2.0) 68 | zeitwerk (~> 2.3) 69 | builder (3.2.4) 70 | bump (0.8.0) 71 | concurrent-ruby (1.1.9) 72 | crass (1.0.6) 73 | diff-lcs (1.4.4) 74 | erubi (1.10.0) 75 | globalid (1.0.0) 76 | activesupport (>= 5.0) 77 | i18n (1.8.11) 78 | concurrent-ruby (~> 1.0) 79 | loofah (2.13.0) 80 | crass (~> 1.0.2) 81 | nokogiri (>= 1.5.9) 82 | mail (2.7.1) 83 | mini_mime (>= 0.1.1) 84 | marcel (1.0.2) 85 | method_source (1.0.0) 86 | mini_mime (1.1.2) 87 | mini_portile2 (2.8.7) 88 | minitest (5.15.0) 89 | nio4r (2.5.8) 90 | nokogiri (1.16.7) 91 | mini_portile2 (~> 2.8.2) 92 | racc (~> 1.4) 93 | racc (1.8.1) 94 | rack (2.2.3) 95 | rack-test (1.1.0) 96 | rack (>= 1.0, < 3) 97 | rails (6.1.4.4) 98 | actioncable (= 6.1.4.4) 99 | actionmailbox (= 6.1.4.4) 100 | actionmailer (= 6.1.4.4) 101 | actionpack (= 6.1.4.4) 102 | actiontext (= 6.1.4.4) 103 | actionview (= 6.1.4.4) 104 | activejob (= 6.1.4.4) 105 | activemodel (= 6.1.4.4) 106 | activerecord (= 6.1.4.4) 107 | activestorage (= 6.1.4.4) 108 | activesupport (= 6.1.4.4) 109 | bundler (>= 1.15.0) 110 | railties (= 6.1.4.4) 111 | sprockets-rails (>= 2.0.0) 112 | rails-dom-testing (2.0.3) 113 | activesupport (>= 4.2.0) 114 | nokogiri (>= 1.6) 115 | rails-html-sanitizer (1.4.2) 116 | loofah (~> 2.3) 117 | railties (6.1.4.4) 118 | actionpack (= 6.1.4.4) 119 | activesupport (= 6.1.4.4) 120 | method_source 121 | rake (>= 0.13) 122 | thor (~> 1.0) 123 | rake (13.0.6) 124 | rspec (3.10.0) 125 | rspec-core (~> 3.10.0) 126 | rspec-expectations (~> 3.10.0) 127 | rspec-mocks (~> 3.10.0) 128 | rspec-core (3.10.0) 129 | rspec-support (~> 3.10.0) 130 | rspec-expectations (3.10.0) 131 | diff-lcs (>= 1.2.0, < 2.0) 132 | rspec-support (~> 3.10.0) 133 | rspec-mocks (3.10.0) 134 | diff-lcs (>= 1.2.0, < 2.0) 135 | rspec-support (~> 3.10.0) 136 | rspec-support (3.10.0) 137 | sprockets (4.0.2) 138 | concurrent-ruby (~> 1.0) 139 | rack (> 1, < 3) 140 | sprockets-rails (3.4.2) 141 | actionpack (>= 5.2) 142 | activesupport (>= 5.2) 143 | sprockets (>= 3.0.0) 144 | sqlite3 (1.4.4) 145 | thor (1.2.1) 146 | tzinfo (2.0.4) 147 | concurrent-ruby (~> 1.0) 148 | websocket-driver (0.7.5) 149 | websocket-extensions (>= 0.1.0) 150 | websocket-extensions (0.1.5) 151 | wwtd (1.3.0) 152 | zeitwerk (2.5.3) 153 | 154 | PLATFORMS 155 | ruby 156 | 157 | DEPENDENCIES 158 | activerecord (~> 6.1.0) 159 | ar_after_transaction! 160 | bump 161 | rails 162 | rake 163 | rspec (~> 3) 164 | sqlite3 (~> 1.0) 165 | wwtd 166 | 167 | BUNDLED WITH 168 | 2.3.12 169 | -------------------------------------------------------------------------------- /gemfiles/rails7.0.gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | gem 'activerecord', '~>7.0.0' 6 | 7 | gemspec path: '../' 8 | -------------------------------------------------------------------------------- /gemfiles/rails7.0.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .. 3 | specs: 4 | ar_after_transaction (0.13.0) 5 | activerecord (>= 6.1.0, < 8.1) 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | actioncable (7.0.1) 11 | actionpack (= 7.0.1) 12 | activesupport (= 7.0.1) 13 | nio4r (~> 2.0) 14 | websocket-driver (>= 0.6.1) 15 | actionmailbox (7.0.1) 16 | actionpack (= 7.0.1) 17 | activejob (= 7.0.1) 18 | activerecord (= 7.0.1) 19 | activestorage (= 7.0.1) 20 | activesupport (= 7.0.1) 21 | mail (>= 2.7.1) 22 | net-imap 23 | net-pop 24 | net-smtp 25 | actionmailer (7.0.1) 26 | actionpack (= 7.0.1) 27 | actionview (= 7.0.1) 28 | activejob (= 7.0.1) 29 | activesupport (= 7.0.1) 30 | mail (~> 2.5, >= 2.5.4) 31 | net-imap 32 | net-pop 33 | net-smtp 34 | rails-dom-testing (~> 2.0) 35 | actionpack (7.0.1) 36 | actionview (= 7.0.1) 37 | activesupport (= 7.0.1) 38 | rack (~> 2.0, >= 2.2.0) 39 | rack-test (>= 0.6.3) 40 | rails-dom-testing (~> 2.0) 41 | rails-html-sanitizer (~> 1.0, >= 1.2.0) 42 | actiontext (7.0.1) 43 | actionpack (= 7.0.1) 44 | activerecord (= 7.0.1) 45 | activestorage (= 7.0.1) 46 | activesupport (= 7.0.1) 47 | globalid (>= 0.6.0) 48 | nokogiri (>= 1.8.5) 49 | actionview (7.0.1) 50 | activesupport (= 7.0.1) 51 | builder (~> 3.1) 52 | erubi (~> 1.4) 53 | rails-dom-testing (~> 2.0) 54 | rails-html-sanitizer (~> 1.1, >= 1.2.0) 55 | activejob (7.0.1) 56 | activesupport (= 7.0.1) 57 | globalid (>= 0.3.6) 58 | activemodel (7.0.1) 59 | activesupport (= 7.0.1) 60 | activerecord (7.0.1) 61 | activemodel (= 7.0.1) 62 | activesupport (= 7.0.1) 63 | activestorage (7.0.1) 64 | actionpack (= 7.0.1) 65 | activejob (= 7.0.1) 66 | activerecord (= 7.0.1) 67 | activesupport (= 7.0.1) 68 | marcel (~> 1.0) 69 | mini_mime (>= 1.1.0) 70 | activesupport (7.0.1) 71 | concurrent-ruby (~> 1.0, >= 1.0.2) 72 | i18n (>= 1.6, < 2) 73 | minitest (>= 5.1) 74 | tzinfo (~> 2.0) 75 | builder (3.2.4) 76 | bump (0.8.0) 77 | concurrent-ruby (1.1.9) 78 | crass (1.0.6) 79 | diff-lcs (1.4.4) 80 | digest (3.1.0) 81 | erubi (1.10.0) 82 | globalid (1.0.0) 83 | activesupport (>= 5.0) 84 | i18n (1.8.11) 85 | concurrent-ruby (~> 1.0) 86 | io-wait (0.2.1) 87 | loofah (2.13.0) 88 | crass (~> 1.0.2) 89 | nokogiri (>= 1.5.9) 90 | mail (2.7.1) 91 | mini_mime (>= 0.1.1) 92 | marcel (1.0.2) 93 | method_source (1.0.0) 94 | mini_mime (1.1.2) 95 | mini_portile2 (2.8.7) 96 | minitest (5.15.0) 97 | net-imap (0.2.3) 98 | digest 99 | net-protocol 100 | strscan 101 | net-pop (0.1.1) 102 | digest 103 | net-protocol 104 | timeout 105 | net-protocol (0.1.2) 106 | io-wait 107 | timeout 108 | net-smtp (0.3.1) 109 | digest 110 | net-protocol 111 | timeout 112 | nio4r (2.5.8) 113 | nokogiri (1.16.7) 114 | mini_portile2 (~> 2.8.2) 115 | racc (~> 1.4) 116 | racc (1.8.1) 117 | rack (2.2.3) 118 | rack-test (1.1.0) 119 | rack (>= 1.0, < 3) 120 | rails (7.0.1) 121 | actioncable (= 7.0.1) 122 | actionmailbox (= 7.0.1) 123 | actionmailer (= 7.0.1) 124 | actionpack (= 7.0.1) 125 | actiontext (= 7.0.1) 126 | actionview (= 7.0.1) 127 | activejob (= 7.0.1) 128 | activemodel (= 7.0.1) 129 | activerecord (= 7.0.1) 130 | activestorage (= 7.0.1) 131 | activesupport (= 7.0.1) 132 | bundler (>= 1.15.0) 133 | railties (= 7.0.1) 134 | rails-dom-testing (2.0.3) 135 | activesupport (>= 4.2.0) 136 | nokogiri (>= 1.6) 137 | rails-html-sanitizer (1.4.2) 138 | loofah (~> 2.3) 139 | railties (7.0.1) 140 | actionpack (= 7.0.1) 141 | activesupport (= 7.0.1) 142 | method_source 143 | rake (>= 12.2) 144 | thor (~> 1.0) 145 | zeitwerk (~> 2.5) 146 | rake (13.0.6) 147 | rspec (3.10.0) 148 | rspec-core (~> 3.10.0) 149 | rspec-expectations (~> 3.10.0) 150 | rspec-mocks (~> 3.10.0) 151 | rspec-core (3.10.0) 152 | rspec-support (~> 3.10.0) 153 | rspec-expectations (3.10.0) 154 | diff-lcs (>= 1.2.0, < 2.0) 155 | rspec-support (~> 3.10.0) 156 | rspec-mocks (3.10.0) 157 | diff-lcs (>= 1.2.0, < 2.0) 158 | rspec-support (~> 3.10.0) 159 | rspec-support (3.10.0) 160 | sqlite3 (1.4.4) 161 | strscan (3.0.1) 162 | thor (1.2.1) 163 | timeout (0.2.0) 164 | tzinfo (2.0.4) 165 | concurrent-ruby (~> 1.0) 166 | websocket-driver (0.7.5) 167 | websocket-extensions (>= 0.1.0) 168 | websocket-extensions (0.1.5) 169 | wwtd (1.3.0) 170 | zeitwerk (2.5.3) 171 | 172 | PLATFORMS 173 | ruby 174 | 175 | DEPENDENCIES 176 | activerecord (~> 7.0.0) 177 | ar_after_transaction! 178 | bump 179 | rails 180 | rake 181 | rspec (~> 3) 182 | sqlite3 (~> 1.0) 183 | wwtd 184 | 185 | BUNDLED WITH 186 | 2.3.12 187 | -------------------------------------------------------------------------------- /gemfiles/rails7.1.gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | gem 'activerecord', '~>7.1.0' 6 | 7 | gemspec path: '../' 8 | -------------------------------------------------------------------------------- /gemfiles/rails7.1.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .. 3 | specs: 4 | ar_after_transaction (0.13.0) 5 | activerecord (>= 6.1.0, < 8.1) 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | actioncable (7.1.0) 11 | actionpack (= 7.1.0) 12 | activesupport (= 7.1.0) 13 | nio4r (~> 2.0) 14 | websocket-driver (>= 0.6.1) 15 | zeitwerk (~> 2.6) 16 | actionmailbox (7.1.0) 17 | actionpack (= 7.1.0) 18 | activejob (= 7.1.0) 19 | activerecord (= 7.1.0) 20 | activestorage (= 7.1.0) 21 | activesupport (= 7.1.0) 22 | mail (>= 2.7.1) 23 | net-imap 24 | net-pop 25 | net-smtp 26 | actionmailer (7.1.0) 27 | actionpack (= 7.1.0) 28 | actionview (= 7.1.0) 29 | activejob (= 7.1.0) 30 | activesupport (= 7.1.0) 31 | mail (~> 2.5, >= 2.5.4) 32 | net-imap 33 | net-pop 34 | net-smtp 35 | rails-dom-testing (~> 2.2) 36 | actionpack (7.1.0) 37 | actionview (= 7.1.0) 38 | activesupport (= 7.1.0) 39 | nokogiri (>= 1.8.5) 40 | rack (>= 2.2.4) 41 | rack-session (>= 1.0.1) 42 | rack-test (>= 0.6.3) 43 | rails-dom-testing (~> 2.2) 44 | rails-html-sanitizer (~> 1.6) 45 | actiontext (7.1.0) 46 | actionpack (= 7.1.0) 47 | activerecord (= 7.1.0) 48 | activestorage (= 7.1.0) 49 | activesupport (= 7.1.0) 50 | globalid (>= 0.6.0) 51 | nokogiri (>= 1.8.5) 52 | actionview (7.1.0) 53 | activesupport (= 7.1.0) 54 | builder (~> 3.1) 55 | erubi (~> 1.11) 56 | rails-dom-testing (~> 2.2) 57 | rails-html-sanitizer (~> 1.6) 58 | activejob (7.1.0) 59 | activesupport (= 7.1.0) 60 | globalid (>= 0.3.6) 61 | activemodel (7.1.0) 62 | activesupport (= 7.1.0) 63 | activerecord (7.1.0) 64 | activemodel (= 7.1.0) 65 | activesupport (= 7.1.0) 66 | timeout (>= 0.4.0) 67 | activestorage (7.1.0) 68 | actionpack (= 7.1.0) 69 | activejob (= 7.1.0) 70 | activerecord (= 7.1.0) 71 | activesupport (= 7.1.0) 72 | marcel (~> 1.0) 73 | activesupport (7.1.0) 74 | base64 75 | bigdecimal 76 | concurrent-ruby (~> 1.0, >= 1.0.2) 77 | connection_pool (>= 2.2.5) 78 | drb 79 | i18n (>= 1.6, < 2) 80 | minitest (>= 5.1) 81 | mutex_m 82 | tzinfo (~> 2.0) 83 | base64 (0.1.1) 84 | bigdecimal (3.1.4) 85 | builder (3.2.4) 86 | bump (0.10.0) 87 | concurrent-ruby (1.2.2) 88 | connection_pool (2.4.1) 89 | crass (1.0.6) 90 | date (3.3.3) 91 | diff-lcs (1.5.0) 92 | drb (2.1.1) 93 | ruby2_keywords 94 | erubi (1.12.0) 95 | globalid (1.2.1) 96 | activesupport (>= 6.1) 97 | i18n (1.14.1) 98 | concurrent-ruby (~> 1.0) 99 | io-console (0.6.0) 100 | irb (1.8.1) 101 | rdoc 102 | reline (>= 0.3.8) 103 | loofah (2.21.3) 104 | crass (~> 1.0.2) 105 | nokogiri (>= 1.12.0) 106 | mail (2.8.1) 107 | mini_mime (>= 0.1.1) 108 | net-imap 109 | net-pop 110 | net-smtp 111 | marcel (1.0.2) 112 | mini_mime (1.1.5) 113 | minitest (5.20.0) 114 | mutex_m (0.1.2) 115 | net-imap (0.4.0) 116 | date 117 | net-protocol 118 | net-pop (0.1.2) 119 | net-protocol 120 | net-protocol (0.2.1) 121 | timeout 122 | net-smtp (0.4.0) 123 | net-protocol 124 | nio4r (2.5.9) 125 | nokogiri (1.16.7-arm64-darwin) 126 | racc (~> 1.4) 127 | nokogiri (1.16.7-x86_64-linux) 128 | racc (~> 1.4) 129 | psych (5.1.0) 130 | stringio 131 | racc (1.8.1) 132 | rack (3.0.8) 133 | rack-session (2.0.0) 134 | rack (>= 3.0.0) 135 | rack-test (2.1.0) 136 | rack (>= 1.3) 137 | rackup (2.1.0) 138 | rack (>= 3) 139 | webrick (~> 1.8) 140 | rails (7.1.0) 141 | actioncable (= 7.1.0) 142 | actionmailbox (= 7.1.0) 143 | actionmailer (= 7.1.0) 144 | actionpack (= 7.1.0) 145 | actiontext (= 7.1.0) 146 | actionview (= 7.1.0) 147 | activejob (= 7.1.0) 148 | activemodel (= 7.1.0) 149 | activerecord (= 7.1.0) 150 | activestorage (= 7.1.0) 151 | activesupport (= 7.1.0) 152 | bundler (>= 1.15.0) 153 | railties (= 7.1.0) 154 | rails-dom-testing (2.2.0) 155 | activesupport (>= 5.0.0) 156 | minitest 157 | nokogiri (>= 1.6) 158 | rails-html-sanitizer (1.6.0) 159 | loofah (~> 2.21) 160 | nokogiri (~> 1.14) 161 | railties (7.1.0) 162 | actionpack (= 7.1.0) 163 | activesupport (= 7.1.0) 164 | irb 165 | rackup (>= 1.0.0) 166 | rake (>= 12.2) 167 | thor (~> 1.0, >= 1.2.2) 168 | zeitwerk (~> 2.6) 169 | rake (13.0.6) 170 | rdoc (6.5.0) 171 | psych (>= 4.0.0) 172 | reline (0.3.9) 173 | io-console (~> 0.5) 174 | rspec (3.12.0) 175 | rspec-core (~> 3.12.0) 176 | rspec-expectations (~> 3.12.0) 177 | rspec-mocks (~> 3.12.0) 178 | rspec-core (3.12.2) 179 | rspec-support (~> 3.12.0) 180 | rspec-expectations (3.12.3) 181 | diff-lcs (>= 1.2.0, < 2.0) 182 | rspec-support (~> 3.12.0) 183 | rspec-mocks (3.12.6) 184 | diff-lcs (>= 1.2.0, < 2.0) 185 | rspec-support (~> 3.12.0) 186 | rspec-support (3.12.1) 187 | ruby2_keywords (0.0.5) 188 | sqlite3 (1.7.3-arm64-darwin) 189 | sqlite3 (1.7.3-x86_64-linux) 190 | stringio (3.0.8) 191 | thor (1.2.2) 192 | timeout (0.4.0) 193 | tzinfo (2.0.6) 194 | concurrent-ruby (~> 1.0) 195 | webrick (1.8.1) 196 | websocket-driver (0.7.6) 197 | websocket-extensions (>= 0.1.0) 198 | websocket-extensions (0.1.5) 199 | wwtd (1.4.1) 200 | zeitwerk (2.6.12) 201 | 202 | PLATFORMS 203 | arm64-darwin-21 204 | arm64-darwin-23 205 | x86_64-linux 206 | 207 | DEPENDENCIES 208 | activerecord (~> 7.1.0) 209 | ar_after_transaction! 210 | bump 211 | rails 212 | rake 213 | rspec (~> 3) 214 | sqlite3 (~> 1.0) 215 | wwtd 216 | 217 | BUNDLED WITH 218 | 2.3.12 219 | -------------------------------------------------------------------------------- /gemfiles/rails7.2.gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | gem 'activerecord', '~>7.2.0' 6 | 7 | gemspec path: '../' 8 | -------------------------------------------------------------------------------- /gemfiles/rails7.2.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .. 3 | specs: 4 | ar_after_transaction (0.13.0) 5 | activerecord (>= 6.1.0, < 8.1) 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | actioncable (7.2.0) 11 | actionpack (= 7.2.0) 12 | activesupport (= 7.2.0) 13 | nio4r (~> 2.0) 14 | websocket-driver (>= 0.6.1) 15 | zeitwerk (~> 2.6) 16 | actionmailbox (7.2.0) 17 | actionpack (= 7.2.0) 18 | activejob (= 7.2.0) 19 | activerecord (= 7.2.0) 20 | activestorage (= 7.2.0) 21 | activesupport (= 7.2.0) 22 | mail (>= 2.8.0) 23 | actionmailer (7.2.0) 24 | actionpack (= 7.2.0) 25 | actionview (= 7.2.0) 26 | activejob (= 7.2.0) 27 | activesupport (= 7.2.0) 28 | mail (>= 2.8.0) 29 | rails-dom-testing (~> 2.2) 30 | actionpack (7.2.0) 31 | actionview (= 7.2.0) 32 | activesupport (= 7.2.0) 33 | nokogiri (>= 1.8.5) 34 | racc 35 | rack (>= 2.2.4, < 3.2) 36 | rack-session (>= 1.0.1) 37 | rack-test (>= 0.6.3) 38 | rails-dom-testing (~> 2.2) 39 | rails-html-sanitizer (~> 1.6) 40 | useragent (~> 0.16) 41 | actiontext (7.2.0) 42 | actionpack (= 7.2.0) 43 | activerecord (= 7.2.0) 44 | activestorage (= 7.2.0) 45 | activesupport (= 7.2.0) 46 | globalid (>= 0.6.0) 47 | nokogiri (>= 1.8.5) 48 | actionview (7.2.0) 49 | activesupport (= 7.2.0) 50 | builder (~> 3.1) 51 | erubi (~> 1.11) 52 | rails-dom-testing (~> 2.2) 53 | rails-html-sanitizer (~> 1.6) 54 | activejob (7.2.0) 55 | activesupport (= 7.2.0) 56 | globalid (>= 0.3.6) 57 | activemodel (7.2.0) 58 | activesupport (= 7.2.0) 59 | activerecord (7.2.0) 60 | activemodel (= 7.2.0) 61 | activesupport (= 7.2.0) 62 | timeout (>= 0.4.0) 63 | activestorage (7.2.0) 64 | actionpack (= 7.2.0) 65 | activejob (= 7.2.0) 66 | activerecord (= 7.2.0) 67 | activesupport (= 7.2.0) 68 | marcel (~> 1.0) 69 | activesupport (7.2.0) 70 | base64 71 | bigdecimal 72 | concurrent-ruby (~> 1.0, >= 1.3.1) 73 | connection_pool (>= 2.2.5) 74 | drb 75 | i18n (>= 1.6, < 2) 76 | logger (>= 1.4.2) 77 | minitest (>= 5.1) 78 | securerandom (>= 0.3) 79 | tzinfo (~> 2.0, >= 2.0.5) 80 | base64 (0.2.0) 81 | bigdecimal (3.1.8) 82 | builder (3.3.0) 83 | bump (0.10.0) 84 | concurrent-ruby (1.3.4) 85 | connection_pool (2.4.1) 86 | crass (1.0.6) 87 | date (3.3.4) 88 | diff-lcs (1.5.1) 89 | drb (2.2.1) 90 | erubi (1.13.0) 91 | globalid (1.2.1) 92 | activesupport (>= 6.1) 93 | i18n (1.14.5) 94 | concurrent-ruby (~> 1.0) 95 | io-console (0.7.2) 96 | irb (1.14.0) 97 | rdoc (>= 4.0.0) 98 | reline (>= 0.4.2) 99 | logger (1.6.0) 100 | loofah (2.22.0) 101 | crass (~> 1.0.2) 102 | nokogiri (>= 1.12.0) 103 | mail (2.8.1) 104 | mini_mime (>= 0.1.1) 105 | net-imap 106 | net-pop 107 | net-smtp 108 | marcel (1.0.4) 109 | mini_mime (1.1.5) 110 | minitest (5.25.1) 111 | net-imap (0.4.14) 112 | date 113 | net-protocol 114 | net-pop (0.1.2) 115 | net-protocol 116 | net-protocol (0.2.2) 117 | timeout 118 | net-smtp (0.5.0) 119 | net-protocol 120 | nio4r (2.7.3) 121 | nokogiri (1.16.7-aarch64-linux) 122 | racc (~> 1.4) 123 | nokogiri (1.16.7-arm-linux) 124 | racc (~> 1.4) 125 | nokogiri (1.16.7-arm64-darwin) 126 | racc (~> 1.4) 127 | nokogiri (1.16.7-x86-linux) 128 | racc (~> 1.4) 129 | nokogiri (1.16.7-x86_64-darwin) 130 | racc (~> 1.4) 131 | nokogiri (1.16.7-x86_64-linux) 132 | racc (~> 1.4) 133 | psych (5.1.2) 134 | stringio 135 | racc (1.8.1) 136 | rack (3.1.7) 137 | rack-session (2.0.0) 138 | rack (>= 3.0.0) 139 | rack-test (2.1.0) 140 | rack (>= 1.3) 141 | rackup (2.1.0) 142 | rack (>= 3) 143 | webrick (~> 1.8) 144 | rails (7.2.0) 145 | actioncable (= 7.2.0) 146 | actionmailbox (= 7.2.0) 147 | actionmailer (= 7.2.0) 148 | actionpack (= 7.2.0) 149 | actiontext (= 7.2.0) 150 | actionview (= 7.2.0) 151 | activejob (= 7.2.0) 152 | activemodel (= 7.2.0) 153 | activerecord (= 7.2.0) 154 | activestorage (= 7.2.0) 155 | activesupport (= 7.2.0) 156 | bundler (>= 1.15.0) 157 | railties (= 7.2.0) 158 | rails-dom-testing (2.2.0) 159 | activesupport (>= 5.0.0) 160 | minitest 161 | nokogiri (>= 1.6) 162 | rails-html-sanitizer (1.6.0) 163 | loofah (~> 2.21) 164 | nokogiri (~> 1.14) 165 | railties (7.2.0) 166 | actionpack (= 7.2.0) 167 | activesupport (= 7.2.0) 168 | irb (~> 1.13) 169 | rackup (>= 1.0.0) 170 | rake (>= 12.2) 171 | thor (~> 1.0, >= 1.2.2) 172 | zeitwerk (~> 2.6) 173 | rake (13.2.1) 174 | rdoc (6.7.0) 175 | psych (>= 4.0.0) 176 | reline (0.5.9) 177 | io-console (~> 0.5) 178 | rspec (3.13.0) 179 | rspec-core (~> 3.13.0) 180 | rspec-expectations (~> 3.13.0) 181 | rspec-mocks (~> 3.13.0) 182 | rspec-core (3.13.0) 183 | rspec-support (~> 3.13.0) 184 | rspec-expectations (3.13.1) 185 | diff-lcs (>= 1.2.0, < 2.0) 186 | rspec-support (~> 3.13.0) 187 | rspec-mocks (3.13.1) 188 | diff-lcs (>= 1.2.0, < 2.0) 189 | rspec-support (~> 3.13.0) 190 | rspec-support (3.13.1) 191 | securerandom (0.3.1) 192 | sqlite3 (1.7.3-aarch64-linux) 193 | sqlite3 (1.7.3-arm-linux) 194 | sqlite3 (1.7.3-arm64-darwin) 195 | sqlite3 (1.7.3-x86-linux) 196 | sqlite3 (1.7.3-x86_64-darwin) 197 | sqlite3 (1.7.3-x86_64-linux) 198 | stringio (3.1.1) 199 | thor (1.3.1) 200 | timeout (0.4.1) 201 | tzinfo (2.0.6) 202 | concurrent-ruby (~> 1.0) 203 | useragent (0.16.10) 204 | webrick (1.8.1) 205 | websocket-driver (0.7.6) 206 | websocket-extensions (>= 0.1.0) 207 | websocket-extensions (0.1.5) 208 | wwtd (1.4.1) 209 | zeitwerk (2.6.17) 210 | 211 | PLATFORMS 212 | aarch64-linux 213 | arm-linux 214 | arm64-darwin 215 | x86-linux 216 | x86_64-darwin 217 | x86_64-linux 218 | 219 | DEPENDENCIES 220 | activerecord (~> 7.2.0) 221 | ar_after_transaction! 222 | bump 223 | rails 224 | rake 225 | rspec (~> 3) 226 | sqlite3 (~> 1.0) 227 | wwtd 228 | 229 | BUNDLED WITH 230 | 2.5.14 231 | -------------------------------------------------------------------------------- /gemfiles/rails8.0.gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | gem 'activerecord', '~>8.0.0' 6 | gem 'sqlite3', '~> 2.1' 7 | 8 | gemspec path: '../' 9 | -------------------------------------------------------------------------------- /gemfiles/rails8.0.gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: .. 3 | specs: 4 | ar_after_transaction (0.13.0) 5 | activerecord (>= 6.1.0, < 8.1) 6 | 7 | GEM 8 | remote: https://rubygems.org/ 9 | specs: 10 | actioncable (8.0.0) 11 | actionpack (= 8.0.0) 12 | activesupport (= 8.0.0) 13 | nio4r (~> 2.0) 14 | websocket-driver (>= 0.6.1) 15 | zeitwerk (~> 2.6) 16 | actionmailbox (8.0.0) 17 | actionpack (= 8.0.0) 18 | activejob (= 8.0.0) 19 | activerecord (= 8.0.0) 20 | activestorage (= 8.0.0) 21 | activesupport (= 8.0.0) 22 | mail (>= 2.8.0) 23 | actionmailer (8.0.0) 24 | actionpack (= 8.0.0) 25 | actionview (= 8.0.0) 26 | activejob (= 8.0.0) 27 | activesupport (= 8.0.0) 28 | mail (>= 2.8.0) 29 | rails-dom-testing (~> 2.2) 30 | actionpack (8.0.0) 31 | actionview (= 8.0.0) 32 | activesupport (= 8.0.0) 33 | nokogiri (>= 1.8.5) 34 | rack (>= 2.2.4) 35 | rack-session (>= 1.0.1) 36 | rack-test (>= 0.6.3) 37 | rails-dom-testing (~> 2.2) 38 | rails-html-sanitizer (~> 1.6) 39 | useragent (~> 0.16) 40 | actiontext (8.0.0) 41 | actionpack (= 8.0.0) 42 | activerecord (= 8.0.0) 43 | activestorage (= 8.0.0) 44 | activesupport (= 8.0.0) 45 | globalid (>= 0.6.0) 46 | nokogiri (>= 1.8.5) 47 | actionview (8.0.0) 48 | activesupport (= 8.0.0) 49 | builder (~> 3.1) 50 | erubi (~> 1.11) 51 | rails-dom-testing (~> 2.2) 52 | rails-html-sanitizer (~> 1.6) 53 | activejob (8.0.0) 54 | activesupport (= 8.0.0) 55 | globalid (>= 0.3.6) 56 | activemodel (8.0.0) 57 | activesupport (= 8.0.0) 58 | activerecord (8.0.0) 59 | activemodel (= 8.0.0) 60 | activesupport (= 8.0.0) 61 | timeout (>= 0.4.0) 62 | activestorage (8.0.0) 63 | actionpack (= 8.0.0) 64 | activejob (= 8.0.0) 65 | activerecord (= 8.0.0) 66 | activesupport (= 8.0.0) 67 | marcel (~> 1.0) 68 | activesupport (8.0.0) 69 | base64 70 | benchmark (>= 0.3) 71 | bigdecimal 72 | concurrent-ruby (~> 1.0, >= 1.3.1) 73 | connection_pool (>= 2.2.5) 74 | drb 75 | i18n (>= 1.6, < 2) 76 | logger (>= 1.4.2) 77 | minitest (>= 5.1) 78 | securerandom (>= 0.3) 79 | tzinfo (~> 2.0, >= 2.0.5) 80 | uri (>= 0.13.1) 81 | base64 (0.2.0) 82 | benchmark (0.4.0) 83 | bigdecimal (3.1.8) 84 | builder (3.3.0) 85 | bump (0.10.0) 86 | concurrent-ruby (1.3.4) 87 | connection_pool (2.4.1) 88 | crass (1.0.6) 89 | date (3.4.1) 90 | diff-lcs (1.5.1) 91 | drb (2.2.1) 92 | erubi (1.13.0) 93 | globalid (1.2.1) 94 | activesupport (>= 6.1) 95 | i18n (1.14.6) 96 | concurrent-ruby (~> 1.0) 97 | io-console (0.8.0) 98 | irb (1.14.1) 99 | rdoc (>= 4.0.0) 100 | reline (>= 0.4.2) 101 | logger (1.6.2) 102 | loofah (2.23.1) 103 | crass (~> 1.0.2) 104 | nokogiri (>= 1.12.0) 105 | mail (2.8.1) 106 | mini_mime (>= 0.1.1) 107 | net-imap 108 | net-pop 109 | net-smtp 110 | marcel (1.0.4) 111 | mini_mime (1.1.5) 112 | minitest (5.25.4) 113 | net-imap (0.5.1) 114 | date 115 | net-protocol 116 | net-pop (0.1.2) 117 | net-protocol 118 | net-protocol (0.2.2) 119 | timeout 120 | net-smtp (0.5.0) 121 | net-protocol 122 | nio4r (2.7.4) 123 | nokogiri (1.17.1-aarch64-linux) 124 | racc (~> 1.4) 125 | nokogiri (1.17.1-arm-linux) 126 | racc (~> 1.4) 127 | nokogiri (1.17.1-arm64-darwin) 128 | racc (~> 1.4) 129 | nokogiri (1.17.1-x86-linux) 130 | racc (~> 1.4) 131 | nokogiri (1.17.1-x86_64-darwin) 132 | racc (~> 1.4) 133 | nokogiri (1.17.1-x86_64-linux) 134 | racc (~> 1.4) 135 | psych (5.2.1) 136 | date 137 | stringio 138 | racc (1.8.1) 139 | rack (3.1.8) 140 | rack-session (2.0.0) 141 | rack (>= 3.0.0) 142 | rack-test (2.1.0) 143 | rack (>= 1.3) 144 | rackup (2.2.1) 145 | rack (>= 3) 146 | rails (8.0.0) 147 | actioncable (= 8.0.0) 148 | actionmailbox (= 8.0.0) 149 | actionmailer (= 8.0.0) 150 | actionpack (= 8.0.0) 151 | actiontext (= 8.0.0) 152 | actionview (= 8.0.0) 153 | activejob (= 8.0.0) 154 | activemodel (= 8.0.0) 155 | activerecord (= 8.0.0) 156 | activestorage (= 8.0.0) 157 | activesupport (= 8.0.0) 158 | bundler (>= 1.15.0) 159 | railties (= 8.0.0) 160 | rails-dom-testing (2.2.0) 161 | activesupport (>= 5.0.0) 162 | minitest 163 | nokogiri (>= 1.6) 164 | rails-html-sanitizer (1.6.1) 165 | loofah (~> 2.21) 166 | nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) 167 | railties (8.0.0) 168 | actionpack (= 8.0.0) 169 | activesupport (= 8.0.0) 170 | irb (~> 1.13) 171 | rackup (>= 1.0.0) 172 | rake (>= 12.2) 173 | thor (~> 1.0, >= 1.2.2) 174 | zeitwerk (~> 2.6) 175 | rake (13.2.1) 176 | rdoc (6.8.1) 177 | psych (>= 4.0.0) 178 | reline (0.5.12) 179 | io-console (~> 0.5) 180 | rspec (3.13.0) 181 | rspec-core (~> 3.13.0) 182 | rspec-expectations (~> 3.13.0) 183 | rspec-mocks (~> 3.13.0) 184 | rspec-core (3.13.2) 185 | rspec-support (~> 3.13.0) 186 | rspec-expectations (3.13.3) 187 | diff-lcs (>= 1.2.0, < 2.0) 188 | rspec-support (~> 3.13.0) 189 | rspec-mocks (3.13.2) 190 | diff-lcs (>= 1.2.0, < 2.0) 191 | rspec-support (~> 3.13.0) 192 | rspec-support (3.13.2) 193 | securerandom (0.4.0) 194 | sqlite3 (2.4.1-aarch64-linux-gnu) 195 | sqlite3 (2.4.1-arm-linux-gnu) 196 | sqlite3 (2.4.1-arm64-darwin) 197 | sqlite3 (2.4.1-x86-linux-gnu) 198 | sqlite3 (2.4.1-x86_64-darwin) 199 | sqlite3 (2.4.1-x86_64-linux-gnu) 200 | stringio (3.1.2) 201 | thor (1.3.2) 202 | timeout (0.4.2) 203 | tzinfo (2.0.6) 204 | concurrent-ruby (~> 1.0) 205 | uri (1.0.2) 206 | useragent (0.16.11) 207 | websocket-driver (0.7.6) 208 | websocket-extensions (>= 0.1.0) 209 | websocket-extensions (0.1.5) 210 | wwtd (1.4.1) 211 | zeitwerk (2.7.1) 212 | 213 | PLATFORMS 214 | aarch64-linux 215 | arm-linux 216 | arm64-darwin 217 | x86-linux 218 | x86_64-darwin 219 | x86_64-linux 220 | 221 | DEPENDENCIES 222 | activerecord (~> 8.0.0) 223 | ar_after_transaction! 224 | bump 225 | rails 226 | rake 227 | rspec (~> 3) 228 | sqlite3 (~> 2.1) 229 | wwtd 230 | 231 | BUNDLED WITH 232 | 2.5.22 233 | -------------------------------------------------------------------------------- /lib/ar_after_transaction.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'active_record' 4 | require 'ar_after_transaction/version' 5 | 6 | module ARAfterTransaction 7 | module ClassMethods 8 | def after_transaction(&block) 9 | connection.after_transaction(&block) 10 | end 11 | 12 | def normally_open_transactions 13 | connection.normally_open_transactions ||= 0 14 | end 15 | 16 | delegate :normally_open_transactions=, to: :connection 17 | 18 | private 19 | 20 | def transactions_open? 21 | connection.send :transactions_open? 22 | end 23 | end 24 | 25 | module InstanceMethods 26 | def after_transaction(&block) 27 | self.class.connection.after_transaction(&block) 28 | end 29 | end 30 | end 31 | 32 | module ARAfterTransactionConnection 33 | def self.included(base) 34 | base.class_eval do 35 | attr_accessor :normally_open_transactions 36 | attr_accessor :after_transaction_callbacks 37 | 38 | alias_method :transaction_without_after, :transaction 39 | alias_method :transaction, :transaction_with_after 40 | end 41 | end 42 | 43 | def transaction_with_after(**args) 44 | clean = true 45 | transaction_without_after(**args) do 46 | yield 47 | rescue ActiveRecord::Rollback 48 | clean = false 49 | raise 50 | end 51 | rescue Exception 52 | clean = false 53 | raise 54 | ensure 55 | unless transactions_open? 56 | callbacks = delete_after_transaction_callbacks 57 | callbacks.each(&:call) if clean 58 | end 59 | end 60 | 61 | def after_transaction(&block) 62 | if transactions_open? 63 | self.after_transaction_callbacks ||= [] 64 | self.after_transaction_callbacks << block 65 | else 66 | yield 67 | end 68 | end 69 | 70 | private 71 | 72 | def transactions_open? 73 | return false unless active? 74 | 75 | self.normally_open_transactions ||= 0 76 | open_transactions > normally_open_transactions 77 | end 78 | 79 | def delete_after_transaction_callbacks 80 | result = after_transaction_callbacks || [] 81 | self.after_transaction_callbacks = [] 82 | result 83 | end 84 | end 85 | 86 | ActiveRecord::Base.extend ARAfterTransaction::ClassMethods 87 | ActiveRecord::Base.include ARAfterTransaction::InstanceMethods 88 | ActiveRecord::ConnectionAdapters::AbstractAdapter.include ARAfterTransactionConnection 89 | -------------------------------------------------------------------------------- /lib/ar_after_transaction/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module ARAfterTransaction 4 | VERSION = '0.13.0' 5 | end 6 | -------------------------------------------------------------------------------- /spec/after_initialize_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'active_record' 4 | require 'rails' 5 | require_relative 'setup_database' 6 | 7 | if ActiveRecord::VERSION::MAJOR > 2 8 | require 'action_controller/railtie' if ActiveRecord::VERSION::MAJOR < 4 9 | 10 | module Passthrough 11 | def self.extended(base) 12 | base.class_eval do 13 | class << self 14 | alias_method :transaction_without_passthrough, :transaction 15 | alias_method :transaction, :transaction_with_passthrough 16 | end 17 | end 18 | end 19 | 20 | def transaction_with_passthrough(**args, &block) 21 | transaction_without_passthrough(**args, &block) 22 | end 23 | end 24 | 25 | class Railtie < ::Rails::Railtie 26 | config.after_initialize do 27 | ActiveRecord::Base.extend Passthrough 28 | end 29 | end 30 | 31 | module ARAfterTransaction 32 | class Application < ::Rails::Application 33 | config.eager_load = false 34 | config.active_support.deprecation = :log 35 | 36 | config.after_initialize do 37 | require 'ar_after_transaction' 38 | end 39 | end 40 | end 41 | 42 | if defined?(Rack::Session::Cookie) 43 | Rack::Session::Cookie.send(:define_method, :warn) { |_| } # silence secret warning 44 | end 45 | ARAfterTransaction::Application.initialize! # initialize app 46 | 47 | class AnExpectedError < RuntimeError; end 48 | 49 | class User 50 | cattr_accessor :test_callbacks, :test_stack 51 | self.test_stack = [] 52 | self.test_callbacks = [] 53 | 54 | after_create :do_it 55 | def do_it 56 | self.class.test_callbacks.map { |callback| send(callback) }.last 57 | end 58 | 59 | def do_after 60 | after_transaction do 61 | ActiveRecord::Base.transaction do 62 | # nested transaction should not cause infinitive recursion 63 | end 64 | self.class.test_stack << :after 65 | end 66 | end 67 | 68 | def do_normal 69 | self.class.test_stack << :normal 70 | end 71 | 72 | def oops 73 | raise AnExpectedError 74 | end 75 | 76 | def raise_rollback 77 | raise ActiveRecord::Rollback 78 | end 79 | end 80 | 81 | describe ARAfterTransaction do 82 | before do 83 | User.normally_open_transactions = nil 84 | expect(User.send(:transactions_open?)).to be_falsey 85 | User.test_stack.clear 86 | User.test_callbacks.clear 87 | end 88 | 89 | it 'has a VERSION' do 90 | expect(ARAfterTransaction::VERSION).to match(/^\d+\.\d+\.\d+$/) 91 | end 92 | 93 | it 'executes after a transaction' do 94 | User.test_callbacks = [:do_after, :do_normal] 95 | User.create! 96 | expect(User.test_stack).to eq [:normal, :after] 97 | end 98 | end 99 | end 100 | -------------------------------------------------------------------------------- /spec/ar_after_transaction_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | class AnExpectedError < RuntimeError; end 6 | 7 | class User 8 | cattr_accessor :test_callbacks, :test_stack 9 | self.test_stack = [] 10 | self.test_callbacks = [] 11 | 12 | after_create :do_it 13 | def do_it 14 | self.class.test_callbacks.map { |callback| send(callback) }.last 15 | end 16 | 17 | def do_after 18 | after_transaction do 19 | ActiveRecord::Base.transaction do 20 | # nested transaction should not cause infinitive recursion 21 | end 22 | self.class.test_stack << :after 23 | end 24 | end 25 | 26 | def do_normal 27 | self.class.test_stack << :normal 28 | end 29 | 30 | def oops 31 | raise AnExpectedError 32 | end 33 | 34 | def raise_rollback 35 | raise ActiveRecord::Rollback 36 | end 37 | 38 | def sigterm 39 | raise SignalException.new('TERM') 40 | end 41 | end 42 | 43 | describe ARAfterTransaction do 44 | before do 45 | User.normally_open_transactions = nil 46 | expect(User.send(:transactions_open?)).to be_falsey 47 | User.test_stack.clear 48 | User.test_callbacks.clear 49 | end 50 | 51 | it 'has a VERSION' do 52 | expect(ARAfterTransaction::VERSION).to match(/^\d+\.\d+\.\d+$/) 53 | end 54 | 55 | it 'executes after a transaction' do 56 | User.test_callbacks = [:do_after, :do_normal] 57 | User.create! 58 | expect(User.test_stack).to eq [:normal, :after] 59 | end 60 | 61 | it 'does not execute when transaction was rolled back by a StandardError' do 62 | User.test_callbacks = [:do_after, :do_normal, :oops] 63 | expect(-> { User.create! }).to raise_error(AnExpectedError) 64 | expect(User.test_stack).to eq [:normal] 65 | end 66 | 67 | it 'does not execute when transaction was rolled back by an Exception' do 68 | User.test_callbacks = [:do_after, :do_normal, :sigterm] 69 | expect(-> { User.create! }).to raise_error(SignalException) 70 | expect(User.test_stack).to eq [:normal] 71 | end 72 | 73 | it 'does not execute when transaction gets rolled back by ActiveRecord::Rollback '\ 74 | 'raised in an after_create callback' do 75 | User.test_callbacks = [:do_after, :do_normal, :raise_rollback] 76 | User.create! 77 | expect(User.test_stack).to eq [:normal] 78 | end 79 | 80 | it 'does not execute when transaction gets rolled back by ActiveRecord::Rollback outside of the model' do 81 | User.test_callbacks = [:do_after, :do_normal] 82 | user = nil 83 | ActiveRecord::Base.transaction do 84 | user = User.create! 85 | raise ActiveRecord::Rollback 86 | end 87 | expect(User.test_stack).to eq [:normal] 88 | end 89 | 90 | it 'clears transaction callbacks when transaction fails' do 91 | User.test_callbacks = [:do_after, :do_normal, :oops] 92 | expect(-> { User.create! }).to raise_error(AnExpectedError) 93 | User.test_callbacks = [:do_normal] 94 | User.create! 95 | expect(User.test_stack).to eq [:normal, :normal] 96 | end 97 | 98 | it 'executes when no transaction is open' do 99 | user = User.new 100 | user.do_after 101 | user.do_normal 102 | expect(User.test_stack).to eq [:after, :normal] 103 | end 104 | 105 | it 'executes when open transactions are normal' do 106 | User.normally_open_transactions = 1 107 | User.test_callbacks = [:do_after, :do_normal] 108 | User.create! 109 | expect(User.test_stack).to eq [:after, :normal] 110 | end 111 | 112 | it 'does not execute the same callback twice when successful' do 113 | User.test_callbacks = [:do_after, :do_normal] 114 | User.create! 115 | User.create! 116 | expect(User.test_stack).to eq [:normal, :after, :normal, :after] 117 | end 118 | 119 | it 'does not execute the same callback twice when failed' do 120 | User.test_callbacks = [:do_after, :do_normal, :oops] 121 | expect(-> { User.create! }).to raise_error(AnExpectedError) 122 | expect(-> { User.create! }).to raise_error(AnExpectedError) 123 | expect(User.test_stack).to eq [:normal, :normal] 124 | end 125 | 126 | it 'does not crash with additional options' do 127 | expect(-> { User.transaction(requires_new: true) { true } }).not_to raise_error 128 | end 129 | 130 | describe '.normally_open_transactions' do 131 | subject(:transactions) { User.normally_open_transactions } 132 | 133 | it 'uses 0 by default' do 134 | expect(transactions).to eq 0 135 | end 136 | 137 | it 'can set normally open transactions' do 138 | User.normally_open_transactions = 5 139 | expect(transactions).to eq 5 140 | end 141 | 142 | it 'sets them globally' do 143 | User.normally_open_transactions = 5 144 | expect(ActiveRecord::Base.normally_open_transactions).to eq 5 145 | end 146 | end 147 | end 148 | 149 | describe 'A normal ActiveRecord subclass' do 150 | it 'does not get polluted' do 151 | expect(User.const_defined?('VERSION')).to be_falsey 152 | end 153 | end 154 | -------------------------------------------------------------------------------- /spec/setup_database.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | ActiveRecord::Base.establish_connection( 4 | adapter: 'sqlite3', 5 | database: ':memory:' 6 | ) 7 | 8 | ActiveRecord::Migration.verbose = false 9 | ActiveRecord::Schema.define(version: 1) do 10 | create_table :users do |t| 11 | t.string :name 12 | t.timestamps null: false 13 | end 14 | end 15 | 16 | # for detailed debugging: 17 | # require 'logger' 18 | # ActiveRecord::Base.logger = Logger.new(STDOUT) 19 | 20 | class User < ActiveRecord::Base; end 21 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'bundler/setup' 4 | require 'ar_after_transaction' 5 | require_relative 'setup_database' 6 | --------------------------------------------------------------------------------