activerecord-transactionable 2.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3becf9bed4568fc5073445b3ae7beb01d86c8e99
4
- data.tar.gz: e771c0221f7ea32ec42a2f4d2628508fd9aa56d2
3
+ metadata.gz: ebf67428aaf44c1ac7ffb5b7515c8e5d927f4966
4
+ data.tar.gz: fe553cbee8e6502b5b68ba04c0a3d296032f1cf4
5
5
  SHA512:
6
- metadata.gz: '019b592ea646a19664e20914d9c3ac42bdd3766fb6f61b4079f6b8d1c36b74542d057570f7322b985f288a7572e3667ba75672311aa55f7c0842f0ad69fff998'
7
- data.tar.gz: 1dd3ac5bc3e1a670c380c1ce6241919e4e313d77249d1cdb279e4d8a0fd49d260134b8a6a5eb50ff62634dce3f6ce7fbf544a328890910f12b1f91e496105513
6
+ metadata.gz: 27f1f73531b9efc309d056c44603c882b4f08e731fb5ed65fd170432aa4a3e64dd4f12785171a36e0828e625b6093ea6edd63a4bea0b3287b67ac4fd9e29fe9b
7
+ data.tar.gz: 70451d8c0c5f4fe156a6153307aad8eca3ff61d063fa0d2b8c3d222897918c7d75cca8ee0f924e1a83c7bb8b4d6af7fc3bf50eb6d8327d3ea0b62e93d585ab49
data/.gitignore CHANGED
@@ -1,4 +1,4 @@
1
- /.bundle/
1
+ .bundle/
2
2
  /.yardoc
3
3
  /Gemfile.lock
4
4
  /_yardoc/
data/README.md CHANGED
@@ -65,7 +65,7 @@ Or install it yourself as:
65
65
 
66
66
  ## Usage
67
67
 
68
- ```
68
+ ```ruby
69
69
  class Car < ActiveRecord::Base
70
70
  include Activerecord::Transactionable # Note lowercase "r" in Activerecord (different namespace than rails' module)
71
71
 
@@ -76,7 +76,8 @@ end
76
76
  When creating, saving, deleting within the transaction make sure to use the bang methods (`!`) in order to ensure a rollback on failure.
77
77
 
78
78
  When everything works:
79
- ```
79
+
80
+ ```ruby
80
81
  car = Car.new(name: "Fiesta")
81
82
  car.transaction_wrapper do
82
83
  car.save!
@@ -85,7 +86,8 @@ car.persisted? # => true
85
86
  ```
86
87
 
87
88
  When something goes wrong:
88
- ```
89
+
90
+ ```ruby
89
91
  car = Car.new(name: nil)
90
92
  car.transaction_wrapper do
91
93
  car.save!
@@ -99,7 +101,8 @@ These examples are too simple to be useful with transactions, but if you are wor
99
101
  Also see the specs.
100
102
 
101
103
  If you need to lock the car as well as have a transaction (note: will reload the `car`):
102
- ```
104
+
105
+ ```ruby
103
106
  car = Car.new(name: nil)
104
107
  car.transaction_wrapper(lock: true) do # uses ActiveRecord's with_lock
105
108
  car.save!
@@ -109,7 +112,8 @@ car.errors.full_messages # => ["Name can't be blank"]
109
112
  ```
110
113
 
111
114
  If you need to know if the transaction succeeded:
112
- ```
115
+
116
+ ```ruby
113
117
  car = Car.new(name: nil)
114
118
  result = car.transaction_wrapper(lock: true) do # uses ActiveRecord's with_lock
115
119
  car.save!
@@ -126,7 +130,7 @@ Meanings of `transaction_wrapper` return values:
126
130
 
127
131
  ## Update Example
128
132
 
129
- ```
133
+ ```ruby
130
134
  @client = Client.find(params[:id])
131
135
  transaction_result = @client.transaction_wrapper(lock: true) do
132
136
  @client.assign_attributes(client_params)
@@ -140,11 +144,41 @@ else
140
144
  end
141
145
  ```
142
146
 
147
+ ## Find or create
148
+
149
+ NOTE: The `is_retry` is passed to the block by the gem, and indicates whether the block is running for the first time or the second time.
150
+ The block will never be retried more than once.
151
+
152
+ ```ruby
153
+ Car.transaction_wrapper(outside_retriable_errors: ActivRecord::RecordNotFound) do |is_retry|
154
+ if is_retry
155
+ Car.create!(vin: vin)
156
+ else
157
+ Car.find_by!(vin: vin)
158
+ end
159
+ end
160
+ ```
161
+
162
+ ## Create or find
163
+
164
+ NOTE: The `is_retry` is passed to the block by the gem, and indicates whether the block is running for the first time or the second time.
165
+ The block will never be retried more than once.
166
+
167
+ ```ruby
168
+ Car.transaction_wrapper(outside_retriable_errors: ActivRecord::RecordNotUnique) do |is_retry|
169
+ if is_retry
170
+ Car.find_by!(vin: vin)
171
+ else
172
+ Car.create!(vin: vin)
173
+ end
174
+ end
175
+ ```
176
+
143
177
  ## Reporting to SAAS Error Tools (like Raygun, etc)
144
178
 
145
179
  Hopefully there will be a better integration at some point, but for now, somewhere in your code do:
146
180
 
147
- ```
181
+ ```ruby
148
182
  module SendToRaygun
149
183
  def transaction_error_logger(**args)
150
184
  super
@@ -74,8 +74,8 @@ module Activerecord # Note lowercase "r" in Activerecord (different namespace th
74
74
  end
75
75
  end
76
76
  error_handler_outside_transaction(object: object, transaction_open: transaction_open, **outside_args) do
77
- run_inside_transaction_block(transaction_args: transaction_args, inside_args: inside_args, lock: lock, transaction_open: transaction_open, object: object) do
78
- yield
77
+ run_inside_transaction_block(transaction_args: transaction_args, inside_args: inside_args, lock: lock, transaction_open: transaction_open, object: object) do |is_retry|
78
+ yield is_retry
79
79
  end
80
80
  end
81
81
  end
@@ -88,22 +88,22 @@ module Activerecord # Note lowercase "r" in Activerecord (different namespace th
88
88
  # Note: with_lock will reload object!
89
89
  # Note: with_lock does not accept arguments like transaction does.
90
90
  object.with_lock do
91
- error_handler_inside_transaction(object: object, transaction_open: transaction_open, **inside_args) do
92
- yield
91
+ error_handler_inside_transaction(object: object, transaction_open: transaction_open, **inside_args) do |is_retry|
92
+ yield is_retry
93
93
  end
94
94
  end
95
95
  else
96
96
  object.transaction(**transaction_args) do
97
- error_handler_inside_transaction(object: object, transaction_open: transaction_open, **inside_args) do
98
- yield
97
+ error_handler_inside_transaction(object: object, transaction_open: transaction_open, **inside_args) do |is_retry|
98
+ yield is_retry
99
99
  end
100
100
  end
101
101
  end
102
102
  else
103
103
  raise ArgumentError, "No object to lock!" if lock
104
104
  ActiveRecord::Base.transaction(**transaction_args) do
105
- error_handler_inside_transaction(object: object, transaction_open: transaction_open, **inside_args) do
106
- yield
105
+ error_handler_inside_transaction(object: object, transaction_open: transaction_open, **inside_args) do |is_retry|
106
+ yield is_retry
107
107
  end
108
108
  end
109
109
  end
@@ -125,8 +125,8 @@ module Activerecord # Note lowercase "r" in Activerecord (different namespace th
125
125
  prepared_errors.concat(DEFAULT_ERRORS_PREPARE_ON_SELF_INSIDE)
126
126
  already_been_added_to_self, needing_added_to_self = rescued_errors.partition {|error_class| prepared_errors.include?(error_class)}
127
127
  local_context = INSIDE_CONTEXT
128
- run_block_with_retry(object, local_context, transaction_open, retriable_errors, reraisable_errors, already_been_added_to_self, needing_added_to_self) do
129
- yield
128
+ run_block_with_retry(object, local_context, transaction_open, retriable_errors, reraisable_errors, already_been_added_to_self, needing_added_to_self) do |is_retry|
129
+ yield is_retry
130
130
  end
131
131
  end
132
132
 
@@ -139,8 +139,8 @@ module Activerecord # Note lowercase "r" in Activerecord (different namespace th
139
139
  prepared_errors.concat(DEFAULT_ERRORS_PREPARE_ON_SELF_OUTSIDE)
140
140
  already_been_added_to_self, needing_added_to_self = rescued_errors.partition {|error_class| prepared_errors.include?(error_class)}
141
141
  local_context = OUTSIDE_CONTEXT
142
- run_block_with_retry(object, local_context, transaction_open, retriable_errors, reraisable_errors, already_been_added_to_self, needing_added_to_self) do
143
- yield
142
+ run_block_with_retry(object, local_context, transaction_open, retriable_errors, reraisable_errors, already_been_added_to_self, needing_added_to_self) do |is_retry|
143
+ yield is_retry
144
144
  end
145
145
  end
146
146
 
@@ -153,7 +153,10 @@ module Activerecord # Note lowercase "r" in Activerecord (different namespace th
153
153
  # If the error is not rescued higher up the error will continue to bubble
154
154
  # If we were already inside a transaction, such that this one is nested,
155
155
  # then the result of the yield is what we want to return, to preserve the innermost result
156
- result = yield
156
+ # We pass the retry state along to yield so that the code implementing
157
+ # the transaction_wrapper can switch behavior on a retry
158
+ # (e.g. create => find)
159
+ result = yield re_try
157
160
  # When in the outside context we need to preserve the inside result so it bubbles up unmolested with the "meaningful" result of the transaction.
158
161
  if result.is_a?(Activerecord::Transactionable::Result)
159
162
  result # <= preserve the meaningful return value
@@ -1,5 +1,5 @@
1
1
  module Activerecord
2
2
  module Transactionable
3
- VERSION = "2.0.0"
3
+ VERSION = "2.0.1"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-transactionable
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Boling
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-11-05 00:00:00.000000000 Z
11
+ date: 2018-01-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel