paper_trail 3.0.9 → 4.0.0.beta1

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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rspec +1 -2
  4. data/.travis.yml +5 -0
  5. data/CHANGELOG.md +37 -23
  6. data/README.md +170 -63
  7. data/gemfiles/3.0.gemfile +10 -4
  8. data/lib/generators/paper_trail/install_generator.rb +19 -3
  9. data/lib/generators/paper_trail/templates/add_transaction_id_column_to_versions.rb +11 -0
  10. data/lib/generators/paper_trail/templates/create_version_associations.rb +17 -0
  11. data/lib/paper_trail.rb +24 -4
  12. data/lib/paper_trail/cleaner.rb +3 -3
  13. data/lib/paper_trail/config.rb +17 -0
  14. data/lib/paper_trail/frameworks/active_record/models/paper_trail/version_association.rb +7 -0
  15. data/lib/paper_trail/frameworks/rails.rb +1 -0
  16. data/lib/paper_trail/frameworks/rspec.rb +5 -0
  17. data/lib/paper_trail/has_paper_trail.rb +112 -38
  18. data/lib/paper_trail/version_association_concern.rb +13 -0
  19. data/lib/paper_trail/version_concern.rb +145 -38
  20. data/lib/paper_trail/version_number.rb +3 -3
  21. data/paper_trail.gemspec +11 -4
  22. data/spec/generators/install_generator_spec.rb +4 -4
  23. data/spec/models/fluxor_spec.rb +19 -0
  24. data/spec/models/gadget_spec.rb +10 -10
  25. data/spec/models/joined_version_spec.rb +9 -9
  26. data/spec/models/post_with_status_spec.rb +3 -3
  27. data/spec/models/version_spec.rb +49 -71
  28. data/spec/models/widget_spec.rb +124 -71
  29. data/spec/modules/version_concern_spec.rb +8 -8
  30. data/spec/modules/version_number_spec.rb +16 -16
  31. data/spec/paper_trail_spec.rb +17 -17
  32. data/spec/rails_helper.rb +34 -0
  33. data/spec/requests/articles_spec.rb +11 -11
  34. data/spec/spec_helper.rb +77 -36
  35. data/test/dummy/app/models/animal.rb +0 -2
  36. data/test/dummy/app/models/book.rb +4 -0
  37. data/test/dummy/app/models/customer.rb +4 -0
  38. data/test/dummy/app/models/editor.rb +4 -0
  39. data/test/dummy/app/models/editorship.rb +5 -0
  40. data/test/dummy/app/models/line_item.rb +4 -0
  41. data/test/dummy/app/models/order.rb +5 -0
  42. data/test/dummy/app/models/person.rb +1 -1
  43. data/test/dummy/app/models/post.rb +0 -1
  44. data/test/dummy/app/models/song.rb +0 -20
  45. data/test/dummy/app/models/widget.rb +4 -0
  46. data/test/dummy/config/application.rb +3 -0
  47. data/test/dummy/config/initializers/paper_trail.rb +1 -1
  48. data/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb +41 -0
  49. data/test/dummy/db/schema.rb +95 -25
  50. data/test/dummy/public/404.html +26 -0
  51. data/test/dummy/public/422.html +26 -0
  52. data/test/dummy/public/500.html +26 -0
  53. data/test/dummy/public/favicon.ico +0 -0
  54. data/test/dummy/public/javascripts/application.js +2 -0
  55. data/test/dummy/public/javascripts/controls.js +965 -0
  56. data/test/dummy/public/javascripts/dragdrop.js +974 -0
  57. data/test/dummy/public/javascripts/effects.js +1123 -0
  58. data/test/dummy/public/javascripts/rails.js +175 -0
  59. data/test/dummy/public/stylesheets/.gitkeep +0 -0
  60. data/test/test_helper.rb +2 -2
  61. data/test/time_travel_helper.rb +15 -0
  62. data/test/unit/model_test.rb +613 -185
  63. data/test/unit/serializer_test.rb +3 -3
  64. metadata +104 -54
  65. data/spec/models/animal_spec.rb +0 -19
  66. data/test/dummy/public/javascripts/prototype.js +0 -6001
@@ -0,0 +1,13 @@
1
+ require 'active_support/concern'
2
+
3
+ module PaperTrail
4
+ module VersionAssociationConcern
5
+ extend ::ActiveSupport::Concern
6
+
7
+ included do
8
+ belongs_to :version
9
+
10
+ attr_accessible :version_id, :foreign_key_name, :foreign_key_id if PaperTrail.active_record_protected_attributes?
11
+ end
12
+ end
13
+ end
@@ -6,10 +6,15 @@ module PaperTrail
6
6
 
7
7
  included do
8
8
  belongs_to :item, :polymorphic => true
9
+ has_many :version_associations, :dependent => :destroy
10
+
9
11
  validates_presence_of :event
10
- attr_accessible :item_type, :item_id, :event, :whodunnit, :object, :object_changes if PaperTrail.active_record_protected_attributes?
12
+
13
+ attr_accessible :item_type, :item_id, :event, :whodunnit, :object, :object_changes, :transaction_id, :created_at if PaperTrail.active_record_protected_attributes?
11
14
 
12
15
  after_create :enforce_version_limit!
16
+
17
+ scope :within_transaction, lambda { |id| where :transaction_id => id }
13
18
  end
14
19
 
15
20
  module ClassMethods
@@ -102,21 +107,28 @@ module PaperTrail
102
107
 
103
108
  # Restore the item from this version.
104
109
  #
105
- # This will automatically restore all :has_one associations as they were "at the time",
106
- # if they are also being versioned by PaperTrail. NOTE: this isn't always guaranteed
107
- # to work so you can either change the lookback period (from the default 3 seconds) or
108
- # opt out.
110
+ # Optionally this can also restore all :has_one and :has_many (including has_many :through) associations as
111
+ # they were "at the time", if they are also being versioned by PaperTrail.
109
112
  #
110
113
  # Options:
111
- # :has_one set to `false` to opt out of has_one reification.
112
- # set to a float to change the lookback time (check whether your db supports
113
- # sub-second datetimes if you want them).
114
+ # :has_one set to `true` to also reify has_one associations. Default is `false`.
115
+ # :has_many set to `true` to also reify has_many and has_many :through associations.
116
+ # Default is `false`.
117
+ # :mark_for_destruction set to `true` to mark the has_one/has_many associations that did not exist in the
118
+ # reified version for destruction, instead of remove them. Default is `false`.
119
+ # This option is handy for people who want to persist the reified version.
120
+ # :dup `false` default behavior
121
+ # `true` it always create a new object instance. It is useful for comparing two versions of the same object
114
122
  def reify(options = {})
115
123
  return nil if object.nil?
116
124
 
117
125
  without_identity_map do
118
- options[:has_one] = 3 if options[:has_one] == true
119
- options.reverse_merge! :has_one => false
126
+ options.reverse_merge!(
127
+ :version_at => created_at,
128
+ :mark_for_destruction => false,
129
+ :has_one => false,
130
+ :has_many => false
131
+ )
120
132
 
121
133
  attrs = self.class.object_col_is_json? ? object : PaperTrail.serializer.load(object)
122
134
 
@@ -133,7 +145,7 @@ module PaperTrail
133
145
  # `item_type` will be the base class, not the actual subclass.
134
146
  # If `type` is present but empty, the class is the base class.
135
147
 
136
- if item
148
+ if item && options[:dup] != true
137
149
  model = item
138
150
  # Look for attributes that exist in the model and not in this version. These attributes should be set to nil.
139
151
  (model.attribute_names - attrs.keys).each { |k| attrs[k] = nil }
@@ -144,14 +156,14 @@ module PaperTrail
144
156
  model = klass.new
145
157
  end
146
158
 
147
- model.class.unserialize_attributes_for_paper_trail attrs
159
+ if PaperTrail.serialized_attributes?
160
+ model.class.unserialize_attributes_for_paper_trail attrs
161
+ end
148
162
 
149
163
  # Set all the attributes in this version on the model
150
164
  attrs.each do |k, v|
151
165
  if model.has_attribute?(k)
152
166
  model[k.to_sym] = v
153
- elsif model.respond_to?("#{k}=")
154
- model.send("#{k}=", v)
155
167
  else
156
168
  logger.warn "Attribute #{k} does not exist on #{item_type} (Version id: #{id})."
157
169
  end
@@ -160,34 +172,35 @@ module PaperTrail
160
172
  model.send "#{model.class.version_association_name}=", self
161
173
 
162
174
  unless options[:has_one] == false
163
- reify_has_ones model, options[:has_one]
175
+ reify_has_ones model, options
176
+ end
177
+
178
+ unless options[:has_many] == false
179
+ reify_has_manys model, options
164
180
  end
165
181
 
166
182
  model
167
183
  end
168
184
  end
169
185
 
170
- # Returns what changed in this version of the item. Cf. `ActiveModel::Dirty#changes`.
171
- # Returns `nil` if your `versions` table does not have an `object_changes` text column.
186
+ # Returns what changed in this version of the item. `ActiveModel::Dirty#changes`.
187
+ # returns `nil` if your `versions` table does not have an `object_changes` text column.
172
188
  def changeset
173
189
  return nil unless self.class.column_names.include? 'object_changes'
174
190
 
175
191
  _changes = self.class.object_changes_col_is_json? ? object_changes : PaperTrail.serializer.load(object_changes)
176
192
  @changeset ||= HashWithIndifferentAccess.new(_changes).tap do |changes|
177
- item_type.constantize.unserialize_attribute_changes(changes)
193
+ if PaperTrail.serialized_attributes?
194
+ item_type.constantize.unserialize_attribute_changes(changes)
195
+ end
178
196
  end
179
197
  rescue
180
198
  {}
181
199
  end
182
200
 
183
201
  # Returns who put the item into the state stored in this version.
184
- def paper_trail_originator
185
- @paper_trail_originator ||= previous.whodunnit rescue nil
186
- end
187
-
188
202
  def originator
189
- warn "DEPRECATED: use `paper_trail_originator` instead of `originator`. Support for `originator` will be removed in PaperTrail 4.0"
190
- self.paper_trail_originator
203
+ @originator ||= previous.whodunnit rescue nil
191
204
  end
192
205
 
193
206
  # Returns who changed the item from the state it had in this version.
@@ -236,25 +249,119 @@ module PaperTrail
236
249
  # Restore the `model`'s has_one associations as they were when this version was
237
250
  # superseded by the next (because that's what the user was looking at when they
238
251
  # made the change).
239
- #
240
- # The `lookback` sets how many seconds before the model's change we go.
241
- def reify_has_ones(model, lookback)
252
+ def reify_has_ones(model, options = {})
253
+ version_table_name = model.class.paper_trail_version_class.table_name
242
254
  model.class.reflect_on_all_associations(:has_one).each do |assoc|
243
- child = model.send assoc.name
244
- if child.respond_to? :version_at
245
- # N.B. we use version of the child as it was `lookback` seconds before the parent was updated.
246
- # Ideally we want the version of the child as it was just before the parent was updated...
247
- # but until PaperTrail knows which updates are "together" (e.g. parent and child being
248
- # updated on the same form), it's impossible to tell when the overall update started;
249
- # and therefore impossible to know when "just before" was.
250
- if (child_as_it_was = child.version_at(send(PaperTrail.timestamp_field) - lookback.seconds))
251
- child_as_it_was.attributes.each do |k,v|
252
- model.send(assoc.name).send :write_attribute, k.to_sym, v rescue nil
255
+ if assoc.klass.paper_trail_enabled_for_model?
256
+ version = model.class.paper_trail_version_class.joins(:version_associations).
257
+ where("version_associations.foreign_key_name = ?", assoc.foreign_key).
258
+ where("version_associations.foreign_key_id = ?", model.id).
259
+ where("#{version_table_name}.item_type = ?", assoc.class_name).
260
+ where("created_at >= ? OR transaction_id = ?", options[:version_at], transaction_id).
261
+ order("#{version_table_name}.id ASC").first
262
+ if version
263
+ if version.event == 'create'
264
+ if options[:mark_for_destruction]
265
+ model.send(assoc.name).mark_for_destruction if model.send(assoc.name, true)
266
+ else
267
+ model.appear_as_new_record do
268
+ model.send "#{assoc.name}=", nil
269
+ end
270
+ end
271
+ else
272
+ child = version.reify(options.merge(:has_many => false, :has_one => false))
273
+ model.appear_as_new_record do
274
+ model.send "#{assoc.name}=", child
275
+ end
253
276
  end
277
+ end
278
+ end
279
+ end
280
+ end
281
+
282
+ # Restore the `model`'s has_many associations as they were at version_at timestamp
283
+ # We lookup the first child versions after version_at timestamp or in same transaction.
284
+ def reify_has_manys(model, options = {})
285
+ assoc_has_many_through, assoc_has_many_directly =
286
+ model.class.reflect_on_all_associations(:has_many).partition { |assoc| assoc.options[:through] }
287
+ reify_has_many_directly(assoc_has_many_directly, model, options)
288
+ reify_has_many_through(assoc_has_many_through, model, options)
289
+ end
290
+
291
+ # Restore the `model`'s has_many associations not associated through another association
292
+ def reify_has_many_directly(associations, model, options = {})
293
+ version_table_name = model.class.paper_trail_version_class.table_name
294
+ associations.each do |assoc|
295
+ next unless assoc.klass.paper_trail_enabled_for_model?
296
+ version_id_subquery = PaperTrail::VersionAssociation.joins(model.class.version_association_name).
297
+ select("MIN(version_id)").
298
+ where("foreign_key_name = ?", assoc.foreign_key).
299
+ where("foreign_key_id = ?", model.id).
300
+ where("#{version_table_name}.item_type = ?", assoc.class_name).
301
+ where("created_at >= ? OR transaction_id = ?", options[:version_at], transaction_id).
302
+ group("item_id").to_sql
303
+ versions = model.class.paper_trail_version_class.where("id IN (#{version_id_subquery})").inject({}) do |acc, v|
304
+ acc.merge!(v.item_id => v)
305
+ end
306
+
307
+ # Pass true to force the model to load
308
+ collection = Array.new model.send(assoc.name, true)
309
+
310
+ # Iterate each child to replace it with the previous value if there is a version after the timestamp
311
+ collection.map! do |c|
312
+ if (version = versions.delete(c.id)).nil?
313
+ c
314
+ elsif version.event == 'create'
315
+ options[:mark_for_destruction] ? c.tap { |r| r.mark_for_destruction } : nil
316
+ else
317
+ version.reify(options.merge(:has_many => false, :has_one => false))
318
+ end
319
+ end
320
+
321
+ # Reify the rest of the versions and add them to the collection, these versions are for those that
322
+ # have been removed from the live associations
323
+ collection += versions.values.map { |version| version.reify(options.merge(:has_many => false, :has_one => false)) }
324
+
325
+ model.send(assoc.name).proxy_association.target = collection.compact
326
+ end
327
+ end
328
+
329
+ # Restore the `model`'s has_many associations through another association
330
+ # This must be called after the direct has_manys have been reified (reify_has_many_directly)
331
+ def reify_has_many_through(associations, model, options = {})
332
+ associations.each do |assoc|
333
+ next unless assoc.klass.paper_trail_enabled_for_model?
334
+ through_collection = model.send(assoc.options[:through])
335
+ collection_keys = through_collection.map { |through_model| through_model.send(assoc.foreign_key) }
336
+
337
+ version_id_subquery = assoc.klass.paper_trail_version_class.
338
+ select("MIN(id)").
339
+ where("item_type = ?", assoc.class_name).
340
+ where("item_id IN (?)", collection_keys).
341
+ where("created_at >= ? OR transaction_id = ?", options[:version_at], transaction_id).
342
+ group("item_id").to_sql
343
+ versions = assoc.klass.paper_trail_version_class.where("id IN (#{version_id_subquery})").inject({}) do |acc, v|
344
+ acc.merge!(v.item_id => v)
345
+ end
346
+
347
+ collection = Array.new assoc.klass.where(assoc.klass.primary_key => collection_keys)
348
+
349
+ # Iterate each child to replace it with the previous value if there is a version after the timestamp
350
+ collection.map! do |c|
351
+ if (version = versions.delete(c.id)).nil?
352
+ c
353
+ elsif version.event == 'create'
354
+ options[:mark_for_destruction] ? c.tap { |r| r.mark_for_destruction } : nil
254
355
  else
255
- model.send "#{assoc.name}=", nil
356
+ version.reify(options.merge(:has_many => false, :has_one => false))
256
357
  end
257
358
  end
359
+
360
+ # Reify the rest of the versions and add them to the collection, these versions are for those that
361
+ # have been removed from the live associations
362
+ collection += versions.values.map { |version| version.reify(options.merge(:has_many => false, :has_one => false)) }
363
+
364
+ model.send(assoc.name).proxy_association.target = collection.compact
258
365
  end
259
366
  end
260
367
 
@@ -1,9 +1,9 @@
1
1
  module PaperTrail
2
2
  module VERSION
3
- MAJOR = 3
3
+ MAJOR = 4
4
4
  MINOR = 0
5
- TINY = 9
6
- PRE = nil
5
+ TINY = 0
6
+ PRE = 'beta1'
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
9
9
 
data/paper_trail.gemspec CHANGED
@@ -19,20 +19,27 @@ Gem::Specification.new do |s|
19
19
 
20
20
  s.required_rubygems_version = '>= 1.3.6'
21
21
 
22
- s.add_dependency 'activerecord', ['>= 3.0', '< 5.0']
23
- s.add_dependency 'activesupport', ['>= 3.0', '< 5.0']
22
+ s.add_dependency 'activerecord', ['>= 3.0', '< 6.0']
23
+ s.add_dependency 'activesupport', ['>= 3.0', '< 6.0']
24
24
 
25
25
  s.add_development_dependency 'rake', '~> 10.1.1'
26
26
  s.add_development_dependency 'shoulda', '~> 3.5'
27
27
  # s.add_development_dependency 'shoulda-matchers', '~> 1.5' # needed for ActiveRecord < 4
28
- s.add_development_dependency 'ffaker', '<= 1.31.0'
28
+ s.add_development_dependency 'ffaker', '>= 1.15'
29
29
  s.add_development_dependency 'railties', ['>= 3.0', '< 5.0']
30
30
  s.add_development_dependency 'sinatra', '~> 1.0'
31
31
  s.add_development_dependency 'rack-test', '>= 0.6'
32
- s.add_development_dependency 'rspec-rails', '~> 2.14'
32
+ s.add_development_dependency 'rspec-rails', '~> 3.1.0'
33
33
  s.add_development_dependency 'generator_spec'
34
34
  s.add_development_dependency 'database_cleaner', '~> 1.2'
35
35
 
36
+ # Allow time travel in testing. timecop is only supported after 1.9.2 but does a better cleanup at 'return'
37
+ if RUBY_VERSION < "1.9.2"
38
+ s.add_development_dependency 'delorean'
39
+ else
40
+ s.add_development_dependency 'timecop'
41
+ end
42
+
36
43
  # JRuby support for the test ENV
37
44
  unless defined?(JRUBY_VERSION)
38
45
  s.add_development_dependency 'sqlite3', '~> 1.2'
@@ -1,4 +1,4 @@
1
- require 'spec_helper'
1
+ require 'rails_helper'
2
2
  require 'generator_spec/test_case'
3
3
  require File.expand_path('../../../lib/generators/paper_trail/install_generator', __FILE__)
4
4
 
@@ -15,7 +15,7 @@ describe PaperTrail::InstallGenerator, :type => :generator do
15
15
  end
16
16
 
17
17
  it "generates a migration for creating the 'versions' table" do
18
- destination_root.should have_structure {
18
+ expect(destination_root).to have_structure {
19
19
  directory 'db' do
20
20
  directory 'migrate' do
21
21
  migration 'create_versions' do
@@ -36,7 +36,7 @@ describe PaperTrail::InstallGenerator, :type => :generator do
36
36
  end
37
37
 
38
38
  it "generates a migration for creating the 'versions' table" do
39
- destination_root.should have_structure {
39
+ expect(destination_root).to have_structure {
40
40
  directory 'db' do
41
41
  directory 'migrate' do
42
42
  migration 'create_versions' do
@@ -50,7 +50,7 @@ describe PaperTrail::InstallGenerator, :type => :generator do
50
50
  end
51
51
 
52
52
  it "generates a migration for adding the 'object_changes' column to the 'versions' table" do
53
- destination_root.should have_structure {
53
+ expect(destination_root).to have_structure {
54
54
  directory 'db' do
55
55
  directory 'migrate' do
56
56
  migration 'add_object_changes_to_versions' do
@@ -0,0 +1,19 @@
1
+ require 'rails_helper'
2
+
3
+ describe Fluxor, :type => :model do
4
+ describe '`be_versioned` matcher' do
5
+ it { is_expected.to_not be_versioned }
6
+ end
7
+
8
+ describe "Methods" do
9
+ describe "Class" do
10
+ subject { Fluxor }
11
+
12
+ describe "#paper_trail_enabled_for_model?" do
13
+ it { is_expected.to respond_to(:paper_trail_enabled_for_model?) }
14
+
15
+ it { expect(subject.paper_trail_enabled_for_model?).to be false }
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,7 +1,7 @@
1
- require 'spec_helper'
1
+ require 'rails_helper'
2
2
 
3
- describe Gadget do
4
- it { should be_versioned }
3
+ describe Gadget, :type => :model do
4
+ it { is_expected.to be_versioned }
5
5
 
6
6
  let(:gadget) { Gadget.create!(:name => 'Wrench', :brand => 'Acme') }
7
7
 
@@ -22,16 +22,16 @@ describe Gadget do
22
22
  describe "Methods" do
23
23
  describe "Instance", :versioning => true do
24
24
  describe "private" do
25
- describe :changed_notably? do
25
+ describe '#changed_notably?' do
26
26
  subject { Gadget.new(:created_at => Time.now) }
27
27
 
28
28
  # apparently the private methods list in Ruby18 is different than in Ruby19+
29
29
  if RUBY_VERSION.to_f >= 1.9
30
- its(:private_methods) { should include(:changed_notably?) }
30
+ it { expect(subject.private_methods).to include(:changed_notably?) }
31
31
  end
32
32
 
33
33
  context "create events" do
34
- it { subject.send(:changed_notably?).should == true }
34
+ it { expect(subject.send(:changed_notably?)).to be true }
35
35
  end
36
36
 
37
37
  context "update events" do
@@ -40,24 +40,24 @@ describe Gadget do
40
40
  context "without update timestamps" do
41
41
  it "should only acknowledge non-ignored attrs" do
42
42
  subject.name = 'Wrench'
43
- subject.send(:changed_notably?).should == true
43
+ expect(subject.send(:changed_notably?)).to be true
44
44
  end
45
45
 
46
46
  it "should not acknowledge ignored attrs and timestamps only" do
47
47
  subject.brand = 'Acme'
48
- subject.send(:changed_notably?).should == false
48
+ expect(subject.send(:changed_notably?)).to be false
49
49
  end
50
50
  end
51
51
 
52
52
  context "with update timestamps" do
53
53
  it "should only acknowledge non-ignored attrs" do
54
54
  subject.name, subject.updated_at = 'Wrench', Time.now
55
- subject.send(:changed_notably?).should == true
55
+ expect(subject.send(:changed_notably?)).to be true
56
56
  end
57
57
 
58
58
  it "should not acknowledge ignored attrs and timestamps only" do
59
59
  subject.brand, subject.updated_at = 'Acme', Time.now
60
- subject.send(:changed_notably?).should == false
60
+ expect(subject.send(:changed_notably?)).to be false
61
61
  end
62
62
  end
63
63
  end
@@ -1,32 +1,32 @@
1
- require 'spec_helper'
1
+ require 'rails_helper'
2
2
 
3
- describe JoinedVersion, :versioning => true do
4
- it { JoinedVersion.superclass.should == PaperTrail::Version }
3
+ describe JoinedVersion, :type => :model, :versioning => true do
4
+ it { expect(JoinedVersion.superclass).to be PaperTrail::Version }
5
5
 
6
6
  let(:widget) { Widget.create!(:name => Faker::Name.name) }
7
7
  let(:version) { JoinedVersion.first }
8
8
 
9
9
  describe "Scopes" do
10
10
  describe "default_scope" do
11
- it { JoinedVersion.default_scopes.should_not be_empty }
11
+ it { expect(JoinedVersion.default_scopes).not_to be_empty }
12
12
  end
13
13
 
14
14
  describe "VersionConcern::ClassMethods" do
15
15
  before { widget } # persist a widget
16
16
 
17
- describe :subsequent do
17
+ describe '#subsequent' do
18
18
  it "shouldn't error out when there is a default_scope that joins" do
19
19
  JoinedVersion.subsequent(version).first
20
20
  end
21
21
  end
22
22
 
23
- describe :preceding do
23
+ describe '#preceding' do
24
24
  it "shouldn't error out when there is a default scope that joins" do
25
25
  JoinedVersion.preceding(version).first
26
26
  end
27
27
  end
28
28
 
29
- describe :between do
29
+ describe '#between' do
30
30
  it "shouldn't error out when there is a default scope that joins" do
31
31
  JoinedVersion.between(Time.now, 1.minute.from_now).first
32
32
  end
@@ -35,8 +35,8 @@ describe JoinedVersion, :versioning => true do
35
35
  end
36
36
 
37
37
  describe "Methods" do
38
- describe :index do
39
- it { should respond_to(:index) }
38
+ describe '#index' do
39
+ it { is_expected.to respond_to(:index) }
40
40
 
41
41
  it "shouldn't error out when there is a default scope that joins" do
42
42
  widget # persist a widget