statesman 3.3.0 → 3.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4ea9661229864328ca481ff132837554323967d265616d38c295c5fa94ca9103
4
- data.tar.gz: 8974f12e8e70d925f0b35e3753a9977d1ff94a1a76bf05c0a967535037ce6a24
3
+ metadata.gz: 171ee6b0234ee7909d9af5b91ee09e8cb397adac1c1e90db5e53b1e08413d137
4
+ data.tar.gz: fd445775c6f034e067b492e79191803c4b5f48127599e9395374fb7934ea9d8e
5
5
  SHA512:
6
- metadata.gz: ec7c81ee5c313377acaf35c1196ccf74036769bb945c636d93f56d346deda319534ea9dbeff87bbfe84a2f3d71d7a1a4ae3d435d80c2fa46dc43d2ff3304661a
7
- data.tar.gz: 78ed181ce45c7517f8617f61e26c20780f0f2c5b3a04236e4766761b985d42172774d05a54d05bcc2d72bc379eb2f6ed3fe68c122ce8989f19d3d5ba16d286af
6
+ metadata.gz: 0b88f58d64734af53bbf5155059a5f56ad96578c7d7be57e0f4b52b77bf1f57db6629438d91da1acd5068ea456d16893070555a720e1d153f7b5111cfa2f4ce2
7
+ data.tar.gz: 3e07fafb2c37ae74a9c60f38ac186110d7f01e2024ff0361948b8dc039e282845748f31737f25a36d228eb8188788f2f7be8db2e1e2d978486e82153c82a7474
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## v3.4.0, 12 February 2018
2
+
3
+ - When unsetting the `most_recent` flag during a transition, don't assume that transitions have an `updated_at` attribute, but rather allow the "updated timestamp column" to be re-configured or disabled entirely (patch by [@timrogers](https://github.com/timrogers))
4
+
1
5
  ## v3.3.0, 5 January 2018
2
6
 
3
7
  - Touch `updated_at` on transitions when unsetting `most_recent` flag (patch by [@NGMarmaduke](https://github.com/NGMarmaduke))
data/README.md CHANGED
@@ -29,7 +29,7 @@ protection.
29
29
  To get started, just add Statesman to your `Gemfile`, and then run `bundle`:
30
30
 
31
31
  ```ruby
32
- gem 'statesman', '~> 3.3.0'
32
+ gem 'statesman', '~> 3.4.0'
33
33
  ```
34
34
 
35
35
  ## Usage
@@ -137,6 +137,11 @@ Generate the transition model:
137
137
  $ rails g statesman:active_record_transition Order OrderTransition
138
138
  ```
139
139
 
140
+ If you're using the ActiveRecord adapter and decide not to include the default
141
+ `updated_at` column in your transition table, you'll need to configure the
142
+ `updated_timestamp_column` option on the transition class, setting it to another column
143
+ name (e.g. `:updated_on`) or `nil`.
144
+
140
145
  And add an association from the parent model:
141
146
 
142
147
  `app/models/order.rb`:
@@ -1,6 +1,13 @@
1
1
  class <%= klass %> < <%= Statesman::Utils.rails_5_or_higher? ? 'ApplicationRecord' : 'ActiveRecord::Base' %>
2
2
  include Statesman::Adapters::ActiveRecordTransition
3
3
 
4
+ # If your transition table doesn't have the default `updated_at` timestamp column,
5
+ # you'll need to configure the `updated_timestamp_column` option, setting it to
6
+ # another column name (e.g. `:updated_on`) or `nil`.
7
+ #
8
+ # self.updated_timestamp_column = :updated_on
9
+ # self.updated_timestamp_column = nil
10
+
4
11
  <%- unless Statesman::Utils.rails_4_or_higher? -%>
5
12
  attr_accessible :to_state, :metadata, :sort_key
6
13
 
@@ -6,6 +6,10 @@ class Create<%= migration_class_name %> < ActiveRecord::Migration<%= "[#{ActiveR
6
6
  t.integer :sort_key, null: false
7
7
  t.integer :<%= parent_id %>, null: false
8
8
  t.boolean :most_recent<%= ", null: false" if database_supports_partial_indexes? %>
9
+
10
+ # If you decide not to include an updated timestamp column in your transition
11
+ # table, you'll need to configure the `updated_timestamp_column` setting in your
12
+ # migration class.
9
13
  t.timestamps null: false
10
14
  end
11
15
 
@@ -88,11 +88,7 @@ module Statesman
88
88
 
89
89
  def unset_old_most_recent
90
90
  most_recent = transitions_for_parent.where(most_recent: true)
91
- updated_at = if ::ActiveRecord::Base.default_timezone == :utc
92
- Time.now.utc
93
- else
94
- Time.now
95
- end
91
+
96
92
  # Check whether the `most_recent` column allows null values. If it
97
93
  # doesn't, set old records to `false`, otherwise, set them to `NULL`.
98
94
  #
@@ -101,9 +97,9 @@ module Statesman
101
97
  # rather than Rails' opinion of whether the database supports partial
102
98
  # indexes, we're robust to DBs later adding support for partial indexes.
103
99
  if transition_class.columns_hash["most_recent"].null == false
104
- most_recent.update_all(most_recent: false, updated_at: updated_at)
100
+ most_recent.update_all(with_updated_timestamp(most_recent: false))
105
101
  else
106
- most_recent.update_all(most_recent: nil, updated_at: updated_at)
102
+ most_recent.update_all(with_updated_timestamp(most_recent: nil))
107
103
  end
108
104
  end
109
105
 
@@ -125,6 +121,18 @@ module Statesman
125
121
  e.message.include?(@transition_class.table_name) &&
126
122
  (e.message.include?("sort_key") || e.message.include?("most_recent"))
127
123
  end
124
+
125
+ def with_updated_timestamp(params)
126
+ return params if @transition_class.updated_timestamp_column.nil?
127
+
128
+ timestamp = if ::ActiveRecord::Base.default_timezone == :utc
129
+ Time.now.utc
130
+ else
131
+ Time.now
132
+ end
133
+
134
+ params.merge(@transition_class.updated_timestamp_column => timestamp)
135
+ end
128
136
  end
129
137
  end
130
138
  end
@@ -3,8 +3,15 @@ require "json"
3
3
  module Statesman
4
4
  module Adapters
5
5
  module ActiveRecordTransition
6
- def self.included(base)
7
- base.send(:serialize, :metadata, JSON)
6
+ DEFAULT_UPDATED_TIMESTAMP_COLUMN = :updated_at
7
+
8
+ extend ActiveSupport::Concern
9
+
10
+ included do
11
+ serialize :metadata, JSON
12
+
13
+ class_attribute :updated_timestamp_column
14
+ self.updated_timestamp_column = DEFAULT_UPDATED_TIMESTAMP_COLUMN
8
15
  end
9
16
  end
10
17
  end
@@ -1,3 +1,3 @@
1
1
  module Statesman
2
- VERSION = "3.3.0".freeze
2
+ VERSION = "3.4.0".freeze
3
3
  end
data/spec/spec_helper.rb CHANGED
@@ -11,6 +11,7 @@ require "action_controller"
11
11
  require "rspec/rails"
12
12
  require "support/active_record"
13
13
  require "rspec/its"
14
+ require "pry"
14
15
 
15
16
  RSpec.configure do |config|
16
17
  config.raise_errors_for_deprecations!
@@ -163,6 +163,46 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
163
163
  to(change { previous_transition.reload.updated_at })
164
164
  end
165
165
 
166
+ context "with a custom updated timestamp column set" do
167
+ around do |example|
168
+ MyActiveRecordModelTransition.updated_timestamp_column.tap do |original_value|
169
+ MyActiveRecordModelTransition.updated_timestamp_column = :updated_on
170
+ example.run
171
+ MyActiveRecordModelTransition.updated_timestamp_column = original_value
172
+ end
173
+ end
174
+
175
+ it "touches the previous transition's updated_on timestamp" do
176
+ expect { Timecop.freeze(Time.now + 1.day) { create } }.
177
+ to(change { previous_transition.reload.updated_on })
178
+ end
179
+
180
+ it "doesn't update the updated_at column" do
181
+ expect { Timecop.freeze(Time.now + 5.seconds) { create } }.
182
+ to_not(change { previous_transition.reload.updated_at })
183
+ end
184
+ end
185
+
186
+ context "with no updated timestamp column set" do
187
+ around do |example|
188
+ MyActiveRecordModelTransition.updated_timestamp_column.tap do |original_value|
189
+ MyActiveRecordModelTransition.updated_timestamp_column = nil
190
+ example.run
191
+ MyActiveRecordModelTransition.updated_timestamp_column = original_value
192
+ end
193
+ end
194
+
195
+ it "just updates the most_recent" do
196
+ expect { Timecop.freeze(Time.now + 5.seconds) { create } }.
197
+ to(change { previous_transition.reload.most_recent })
198
+ end
199
+
200
+ it "doesn't update the updated_at column" do
201
+ expect { Timecop.freeze(Time.now + 5.seconds) { create } }.
202
+ to_not(change { previous_transition.reload.updated_at })
203
+ end
204
+ end
205
+
166
206
  context "and a query on the parent model's state is made" do
167
207
  context "in a before action" do
168
208
  it "still has the old state" do
@@ -50,7 +50,7 @@ class CreateMyActiveRecordModelMigration < MIGRATION_CLASS
50
50
  end
51
51
 
52
52
  # TODO: make this a module we can extend from the app? Or a generator?
53
- # rubocop:disable MethodLength
53
+ # rubocop:disable MethodLength, Metrics/AbcSize
54
54
  class CreateMyActiveRecordModelTransitionMigration < MIGRATION_CLASS
55
55
  def change
56
56
  create_table :my_active_record_model_transitions do |t|
@@ -72,6 +72,10 @@ class CreateMyActiveRecordModelTransitionMigration < MIGRATION_CLASS
72
72
  end
73
73
 
74
74
  t.timestamps null: false
75
+
76
+ # We'll use this to test customising the updated_timestamp_column setting on the
77
+ # transition class.
78
+ t.date :updated_on
75
79
  end
76
80
 
77
81
  add_index :my_active_record_model_transitions,
@@ -94,7 +98,7 @@ class CreateMyActiveRecordModelTransitionMigration < MIGRATION_CLASS
94
98
  end
95
99
  end
96
100
  end
97
- # rubocop:enable MethodLength
101
+ # rubocop:enable MethodLength, Metrics/AbcSize
98
102
 
99
103
  class OtherActiveRecordModel < ActiveRecord::Base
100
104
  has_many :other_active_record_model_transitions, autosave: false
@@ -206,6 +210,8 @@ module MyNamespace
206
210
  end
207
211
 
208
212
  class MyActiveRecordModelTransition < ActiveRecord::Base
213
+ include Statesman::Adapters::ActiveRecordTransition
214
+
209
215
  belongs_to :my_active_record_model,
210
216
  class_name: "MyNamespace::MyActiveRecordModel"
211
217
  serialize :metadata, JSON
data/statesman.gemspec CHANGED
@@ -23,13 +23,14 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "bundler", "~> 1.3"
24
24
  spec.add_development_dependency "mysql2", "~> 0.4"
25
25
  spec.add_development_dependency "pg", "~> 0.18"
26
+ spec.add_development_dependency "pry"
26
27
  spec.add_development_dependency "rails", ">= 3.2"
27
28
  spec.add_development_dependency "rake", "~> 12.3.0"
28
29
  spec.add_development_dependency "rspec", "~> 3.1"
29
30
  spec.add_development_dependency "rspec-its", "~> 1.1"
30
31
  spec.add_development_dependency "rspec-rails", "~> 3.1"
31
32
  spec.add_development_dependency "rspec_junit_formatter", "~> 0.3.0"
32
- spec.add_development_dependency "rubocop", "~> 0.52.0"
33
- spec.add_development_dependency "sqlite3", "~> 1.3"
34
- spec.add_development_dependency "timecop", "~> 0.9.1"
33
+ spec.add_development_dependency "rubocop", "~> 0.52.0"
34
+ spec.add_development_dependency "sqlite3", "~> 1.3"
35
+ spec.add_development_dependency "timecop", "~> 0.9.1"
35
36
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: statesman
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.0
4
+ version: 3.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GoCardless
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-01-05 00:00:00.000000000 Z
11
+ date: 2018-02-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ammeter
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0.18'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rails
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -279,7 +293,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
279
293
  version: '0'
280
294
  requirements: []
281
295
  rubyforge_project:
282
- rubygems_version: 2.7.3
296
+ rubygems_version: 2.7.4
283
297
  signing_key:
284
298
  specification_version: 4
285
299
  summary: A statesman-like state machine library