paper_trail 4.0.0 → 4.0.1

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.
@@ -7,10 +7,10 @@ module PaperTrail
7
7
  included do
8
8
  belongs_to :item, :polymorphic => true
9
9
 
10
- # Since the test suite has test coverage for this, we want to declare the
11
- # association when the test suite is running. This makes it pass
12
- # when DB is not initialized prior to test runs such as when we run on
13
- # Travis CI (there won't be a db in `test/dummy/db/`)
10
+ # Since the test suite has test coverage for this, we want to declare
11
+ # the association when the test suite is running. This makes it pass when
12
+ # DB is not initialized prior to test runs such as when we run on Travis
13
+ # CI (there won't be a db in `test/dummy/db/`).
14
14
  if PaperTrail.config.track_associations?
15
15
  has_many :version_associations, :dependent => :destroy
16
16
  end
@@ -47,8 +47,8 @@ module PaperTrail
47
47
  where 'event <> ?', 'create'
48
48
  end
49
49
 
50
- # Expects `obj` to be an instance of `PaperTrail::Version` by default, but can accept a timestamp if
51
- # `timestamp_arg` receives `true`
50
+ # Expects `obj` to be an instance of `PaperTrail::Version` by default,
51
+ # but can accept a timestamp if `timestamp_arg` receives `true`
52
52
  def subsequent(obj, timestamp_arg = false)
53
53
  if timestamp_arg != true && self.primary_key_is_int?
54
54
  return where(arel_table[primary_key].gt(obj.id)).order(arel_table[primary_key].asc)
@@ -75,7 +75,8 @@ module PaperTrail
75
75
  ).order(self.timestamp_sort_order)
76
76
  end
77
77
 
78
- # defaults to using the primary key as the secondary sort order if possible
78
+ # Defaults to using the primary key as the secondary sort order if
79
+ # possible.
79
80
  def timestamp_sort_order(direction = 'asc')
80
81
  [arel_table[PaperTrail.timestamp_field].send(direction.downcase)].tap do |array|
81
82
  array << arel_table[primary_key].send(direction.downcase) if self.primary_key_is_int?
@@ -137,12 +138,14 @@ module PaperTrail
137
138
  true
138
139
  end
139
140
 
140
- # Returns whether the `object` column is using the `json` type supported by PostgreSQL
141
+ # Returns whether the `object` column is using the `json` type supported
142
+ # by PostgreSQL.
141
143
  def object_col_is_json?
142
144
  [:json, :jsonb].include?(columns_hash['object'].type)
143
145
  end
144
146
 
145
- # Returns whether the `object_changes` column is using the `json` type supported by PostgreSQL
147
+ # Returns whether the `object_changes` column is using the `json` type
148
+ # supported by PostgreSQL.
146
149
  def object_changes_col_is_json?
147
150
  [:json, :jsonb].include?(columns_hash['object_changes'].try(:type))
148
151
  end
@@ -150,18 +153,31 @@ module PaperTrail
150
153
 
151
154
  # Restore the item from this version.
152
155
  #
153
- # Optionally this can also restore all :has_one and :has_many (including has_many :through) associations as
154
- # they were "at the time", if they are also being versioned by PaperTrail.
156
+ # Optionally this can also restore all :has_one and :has_many (including
157
+ # has_many :through) associations as they were "at the time", if they are
158
+ # also being versioned by PaperTrail.
155
159
  #
156
160
  # Options:
157
- # :has_one set to `true` to also reify has_one associations. Default is `false`.
158
- # :has_many set to `true` to also reify has_many and has_many :through associations.
159
- # Default is `false`.
160
- # :mark_for_destruction set to `true` to mark the has_one/has_many associations that did not exist in the
161
- # reified version for destruction, instead of remove them. Default is `false`.
162
- # This option is handy for people who want to persist the reified version.
163
- # :dup `false` default behavior
164
- # `true` it always create a new object instance. It is useful for comparing two versions of the same object
161
+ #
162
+ # - :has_one
163
+ # - `true` - Also reify has_one associations.
164
+ # - `false - Default.
165
+ # - :has_many
166
+ # - `true` - Also reify has_many and has_many :through associations.
167
+ # - `false` - Default.
168
+ # - :mark_for_destruction
169
+ # - `true` - Mark the has_one/has_many associations that did not exist in
170
+ # the reified version for destruction, instead of removing them.
171
+ # - `false` - Default. Useful for persisting the reified version.
172
+ # - :dup
173
+ # - `false` - Default.
174
+ # - `true` - Always create a new object instance. Useful for
175
+ # comparing two versions of the same object.
176
+ # - :unversioned_attributes
177
+ # - `:nil` - Default. Attributes undefined in version record are set to
178
+ # nil in reified record.
179
+ # - `:preserve` - Attributes undefined in version record are not modified.
180
+ #
165
181
  def reify(options = {})
166
182
  return nil if object.nil?
167
183
 
@@ -170,39 +186,43 @@ module PaperTrail
170
186
  :version_at => created_at,
171
187
  :mark_for_destruction => false,
172
188
  :has_one => false,
173
- :has_many => false
189
+ :has_many => false,
190
+ :unversioned_attributes => :nil
174
191
  )
175
192
 
176
193
  attrs = self.class.object_col_is_json? ? object : PaperTrail.serializer.load(object)
177
194
 
178
- # Normally a polymorphic belongs_to relationship allows us
179
- # to get the object we belong to by calling, in this case,
180
- # `item`. However this returns nil if `item` has been
181
- # destroyed, and we need to be able to retrieve destroyed
182
- # objects.
195
+ # Normally a polymorphic belongs_to relationship allows us to get the
196
+ # object we belong to by calling, in this case, `item`. However this
197
+ # returns nil if `item` has been destroyed, and we need to be able to
198
+ # retrieve destroyed objects.
183
199
  #
184
- # In this situation we constantize the `item_type` to get hold of
185
- # the class...except when the stored object's attributes
186
- # include a `type` key. If this is the case, the object
187
- # we belong to is using single table inheritance and the
188
- # `item_type` will be the base class, not the actual subclass.
189
- # If `type` is present but empty, the class is the base class.
200
+ # In this situation we constantize the `item_type` to get hold of the
201
+ # class...except when the stored object's attributes include a `type`
202
+ # key. If this is the case, the object we belong to is using single
203
+ # table inheritance and the `item_type` will be the base class, not the
204
+ # actual subclass. If `type` is present but empty, the class is the base
205
+ # class.
190
206
 
191
207
  if options[:dup] != true && item
192
208
  model = item
193
- # Look for attributes that exist in the model and not in this version. These attributes should be set to nil.
194
- (model.attribute_names - attrs.keys).each { |k| attrs[k] = nil }
209
+ # Look for attributes that exist in the model and not in this
210
+ # version. These attributes should be set to nil.
211
+ if options[:unversioned_attributes] == :nil
212
+ (model.attribute_names - attrs.keys).each { |k| attrs[k] = nil }
213
+ end
195
214
  else
196
215
  inheritance_column_name = item_type.constantize.inheritance_column
197
216
  class_name = attrs[inheritance_column_name].blank? ? item_type : attrs[inheritance_column_name]
198
217
  klass = class_name.constantize
199
- # the `dup` option always returns a new object, otherwise we should attempt
200
- # to look for the item outside of default scope(s)
218
+ # The `dup` option always returns a new object, otherwise we should
219
+ # attempt to look for the item outside of default scope(s).
201
220
  if options[:dup] || (_item = klass.unscoped.find_by_id(item_id)).nil?
202
221
  model = klass.new
203
- else
222
+ elsif options[:unversioned_attributes] == :nil
204
223
  model = _item
205
- # Look for attributes that exist in the model and not in this version. These attributes should be set to nil.
224
+ # Look for attributes that exist in the model and not in this
225
+ # version. These attributes should be set to nil.
206
226
  (model.attribute_names - attrs.keys).each { |k| attrs[k] = nil }
207
227
  end
208
228
  end
@@ -211,7 +231,7 @@ module PaperTrail
211
231
  model.class.unserialize_attributes_for_paper_trail! attrs
212
232
  end
213
233
 
214
- # Set all the attributes in this version on the model
234
+ # Set all the attributes in this version on the model.
215
235
  attrs.each do |k, v|
216
236
  if model.has_attribute?(k)
217
237
  model[k.to_sym] = v
@@ -236,8 +256,9 @@ module PaperTrail
236
256
  end
237
257
  end
238
258
 
239
- # Returns what changed in this version of the item. `ActiveModel::Dirty#changes`.
240
- # returns `nil` if your `versions` table does not have an `object_changes` text column.
259
+ # Returns what changed in this version of the item.
260
+ # `ActiveModel::Dirty#changes`. returns `nil` if your `versions` table does
261
+ # not have an `object_changes` text column.
241
262
  def changeset
242
263
  return nil unless self.class.column_names.include? 'object_changes'
243
264
 
@@ -261,8 +282,8 @@ module PaperTrail
261
282
  self.paper_trail_originator
262
283
  end
263
284
 
264
- # Returns who changed the item from the state it had in this version.
265
- # This is an alias for `whodunnit`.
285
+ # Returns who changed the item from the state it had in this version. This
286
+ # is an alias for `whodunnit`.
266
287
  def terminator
267
288
  @terminator ||= whodunnit
268
289
  end
@@ -304,9 +325,9 @@ module PaperTrail
304
325
  end
305
326
  end
306
327
 
307
- # Restore the `model`'s has_one associations as they were when this version was
308
- # superseded by the next (because that's what the user was looking at when they
309
- # made the change).
328
+ # Restore the `model`'s has_one associations as they were when this
329
+ # version was superseded by the next (because that's what the user was
330
+ # looking at when they made the change).
310
331
  def reify_has_ones(model, options = {})
311
332
  version_table_name = model.class.paper_trail_version_class.table_name
312
333
  model.class.reflect_on_all_associations(:has_one).each do |assoc|
@@ -337,8 +358,9 @@ module PaperTrail
337
358
  end
338
359
  end
339
360
 
340
- # Restore the `model`'s has_many associations as they were at version_at timestamp
341
- # We lookup the first child versions after version_at timestamp or in same transaction.
361
+ # Restore the `model`'s has_many associations as they were at version_at
362
+ # timestamp We lookup the first child versions after version_at timestamp or
363
+ # in same transaction.
342
364
  def reify_has_manys(model, options = {})
343
365
  assoc_has_many_through, assoc_has_many_directly =
344
366
  model.class.reflect_on_all_associations(:has_many).
@@ -347,7 +369,8 @@ module PaperTrail
347
369
  reify_has_many_through(assoc_has_many_through, model, options)
348
370
  end
349
371
 
350
- # Restore the `model`'s has_many associations not associated through another association
372
+ # Restore the `model`'s has_many associations not associated through
373
+ # another association.
351
374
  def reify_has_many_directly(associations, model, options = {})
352
375
  version_table_name = model.class.paper_trail_version_class.table_name
353
376
  associations.each do |assoc|
@@ -363,10 +386,11 @@ module PaperTrail
363
386
  acc.merge!(v.item_id => v)
364
387
  end
365
388
 
366
- # Pass true to force the model to load
389
+ # Pass true to force the model to load.
367
390
  collection = Array.new model.send(assoc.name, true)
368
391
 
369
- # Iterate each child to replace it with the previous value if there is a version after the timestamp
392
+ # Iterate each child to replace it with the previous value if there is
393
+ # a version after the timestamp.
370
394
  collection.map! do |c|
371
395
  if (version = versions.delete(c.id)).nil?
372
396
  c
@@ -377,16 +401,18 @@ module PaperTrail
377
401
  end
378
402
  end
379
403
 
380
- # Reify the rest of the versions and add them to the collection, these versions are for those that
381
- # have been removed from the live associations
404
+ # Reify the rest of the versions and add them to the collection, these
405
+ # versions are for those that have been removed from the live
406
+ # associations.
382
407
  collection += versions.values.map { |version| version.reify(options.merge(:has_many => false, :has_one => false)) }
383
408
 
384
409
  model.send(assoc.name).proxy_association.target = collection.compact
385
410
  end
386
411
  end
387
412
 
388
- # Restore the `model`'s has_many associations through another association
389
- # This must be called after the direct has_manys have been reified (reify_has_many_directly)
413
+ # Restore the `model`'s has_many associations through another association.
414
+ # This must be called after the direct has_manys have been reified
415
+ # (reify_has_many_directly).
390
416
  def reify_has_many_through(associations, model, options = {})
391
417
  associations.each do |assoc|
392
418
  next unless assoc.klass.paper_trail_enabled_for_model?
@@ -405,7 +431,8 @@ module PaperTrail
405
431
 
406
432
  collection = Array.new assoc.klass.where(assoc.klass.primary_key => collection_keys)
407
433
 
408
- # Iterate each child to replace it with the previous value if there is a version after the timestamp
434
+ # Iterate each child to replace it with the previous value if there is
435
+ # a version after the timestamp.
409
436
  collection.map! do |c|
410
437
  if (version = versions.delete(c.id)).nil?
411
438
  c
@@ -416,15 +443,17 @@ module PaperTrail
416
443
  end
417
444
  end
418
445
 
419
- # Reify the rest of the versions and add them to the collection, these versions are for those that
420
- # have been removed from the live associations
446
+ # Reify the rest of the versions and add them to the collection, these
447
+ # versions are for those that have been removed from the live
448
+ # associations.
421
449
  collection += versions.values.map { |version| version.reify(options.merge(:has_many => false, :has_one => false)) }
422
450
 
423
451
  model.send(assoc.name).proxy_association.target = collection.compact
424
452
  end
425
453
  end
426
454
 
427
- # checks to see if a value has been set for the `version_limit` config option, and if so enforces it
455
+ # Checks that a value has been set for the `version_limit` config
456
+ # option, and if so enforces it.
428
457
  def enforce_version_limit!
429
458
  return unless PaperTrail.config.version_limit.is_a? Numeric
430
459
  previous_versions = sibling_versions.not_creates
@@ -2,7 +2,7 @@ module PaperTrail
2
2
  module VERSION
3
3
  MAJOR = 4
4
4
  MINOR = 0
5
- TINY = 0
5
+ TINY = 1
6
6
  PRE = nil
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
@@ -1,16 +1,45 @@
1
1
  require 'rails_helper'
2
2
 
3
3
  describe Skipper, :type => :model do
4
- describe "#update_attributes!", :versioning => true do
5
- context "updating a skipped attribute" do
6
- let(:t1) { Time.zone.local(2015, 7, 15, 20, 34, 0) }
7
- let(:t2) { Time.zone.local(2015, 7, 15, 20, 34, 30) }
4
+ with_versioning do
5
+ it { is_expected.to be_versioned }
8
6
 
9
- it "should not create a version" do
10
- skipper = Skipper.create!(:another_timestamp => t1)
11
- expect {
12
- skipper.update_attributes!(:another_timestamp => t2)
13
- }.to_not change { skipper.versions.length }
7
+ describe "#update_attributes!", :versioning => true do
8
+ context "updating a skipped attribute" do
9
+ let(:t1) { Time.zone.local(2015, 7, 15, 20, 34, 0) }
10
+ let(:t2) { Time.zone.local(2015, 7, 15, 20, 34, 30) }
11
+
12
+ it "should not create a version" do
13
+ skipper = Skipper.create!(:another_timestamp => t1)
14
+ expect {
15
+ skipper.update_attributes!(:another_timestamp => t2)
16
+ }.to_not change { skipper.versions.length }
17
+ end
18
+ end
19
+ end
20
+
21
+ describe "reify" do
22
+ context "reifying a with a skipped attribute" do
23
+ let(:t1) { Time.zone.local(2015, 7, 15, 20, 34, 0) }
24
+ let(:t2) { Time.zone.local(2015, 7, 15, 20, 34, 30) }
25
+
26
+ context "without preserve (default)" do
27
+ it "should have no timestamp" do
28
+ skipper = Skipper.create!(:another_timestamp => t1)
29
+ skipper.update_attributes!(:another_timestamp => t2, :name => "Foobar")
30
+ skipper = skipper.versions.last.reify
31
+ expect(skipper.another_timestamp).to be(nil)
32
+ end
33
+ end
34
+
35
+ context "with preserve" do
36
+ it "should preserve its timestamp" do
37
+ skipper = Skipper.create!(:another_timestamp => t1)
38
+ skipper.update_attributes!(:another_timestamp => t2, :name => "Foobar")
39
+ skipper = skipper.versions.last.reify(:unversioned_attributes => :preserve)
40
+ expect(skipper.another_timestamp).to eq(t2)
41
+ end
42
+ end
14
43
  end
15
44
  end
16
45
  end
@@ -51,8 +51,8 @@ describe Widget, :type => :model do
51
51
  describe :after_create do
52
52
  let(:widget) { Widget.create!(:name => 'Foobar', :created_at => Time.now - 1.week) }
53
53
 
54
- it "corresponding version should use the widget's `created_at`" do
55
- expect(widget.versions.last.created_at.to_i).to eq(widget.created_at.to_i)
54
+ it "corresponding version should use the widget's `updated_at`" do
55
+ expect(widget.versions.last.created_at.to_i).to eq(widget.updated_at.to_i)
56
56
  end
57
57
  end
58
58
 
@@ -1,7 +1,8 @@
1
1
  class SetUpTestTables < ActiveRecord::Migration
2
2
  def self.up
3
3
  create_table :skippers, :force => true do |t|
4
- t.datetime :another_timestamp
4
+ t.string :name
5
+ t.datetime :another_timestamp
5
6
  t.timestamps :null => true
6
7
  end
7
8
 
@@ -13,77 +13,108 @@
13
13
 
14
14
  ActiveRecord::Schema.define(version: 20110208155312) do
15
15
 
16
- create_table "animals", force: true do |t|
16
+ create_table "animals", force: :cascade do |t|
17
17
  t.string "name"
18
18
  t.string "species"
19
19
  end
20
20
 
21
- create_table "articles", force: true do |t|
21
+ create_table "articles", force: :cascade do |t|
22
22
  t.string "title"
23
23
  t.string "content"
24
24
  t.string "abstract"
25
25
  t.string "file_upload"
26
26
  end
27
27
 
28
- create_table "authorships", force: true do |t|
28
+ create_table "authorships", force: :cascade do |t|
29
29
  t.integer "book_id"
30
30
  t.integer "person_id"
31
31
  end
32
32
 
33
- create_table "books", force: true do |t|
33
+ create_table "banana_versions", force: :cascade do |t|
34
+ t.string "item_type", null: false
35
+ t.integer "item_id", null: false
36
+ t.string "event", null: false
37
+ t.string "whodunnit"
38
+ t.text "object"
39
+ t.datetime "created_at"
40
+ end
41
+
42
+ add_index "banana_versions", ["item_type", "item_id"], name: "index_banana_versions_on_item_type_and_item_id"
43
+
44
+ create_table "bananas", force: :cascade do |t|
45
+ t.datetime "created_at"
46
+ t.datetime "updated_at"
47
+ end
48
+
49
+ create_table "books", force: :cascade do |t|
34
50
  t.string "title"
35
51
  end
36
52
 
37
- create_table "customers", force: true do |t|
53
+ create_table "boolits", force: :cascade do |t|
54
+ t.string "name"
55
+ t.boolean "scoped", default: true
56
+ end
57
+
58
+ create_table "customers", force: :cascade do |t|
38
59
  t.string "name"
39
60
  end
40
61
 
41
- create_table "documents", force: true do |t|
62
+ create_table "documents", force: :cascade do |t|
42
63
  t.string "name"
43
64
  end
44
65
 
45
- create_table "editors", force: true do |t|
66
+ create_table "editors", force: :cascade do |t|
46
67
  t.string "name"
47
68
  end
48
69
 
49
- create_table "editorships", force: true do |t|
70
+ create_table "editorships", force: :cascade do |t|
50
71
  t.integer "book_id"
51
72
  t.integer "editor_id"
52
73
  end
53
74
 
54
- create_table "fluxors", force: true do |t|
75
+ create_table "fluxors", force: :cascade do |t|
55
76
  t.integer "widget_id"
56
77
  t.string "name"
57
78
  end
58
79
 
59
- create_table "gadgets", force: true do |t|
80
+ create_table "fruits", force: :cascade do |t|
81
+ t.string "name"
82
+ t.string "color"
83
+ end
84
+
85
+ create_table "gadgets", force: :cascade do |t|
60
86
  t.string "name"
61
87
  t.string "brand"
62
88
  t.datetime "created_at"
63
89
  t.datetime "updated_at"
64
90
  end
65
91
 
66
- create_table "legacy_widgets", force: true do |t|
92
+ create_table "legacy_widgets", force: :cascade do |t|
67
93
  t.string "name"
68
94
  t.integer "version"
69
95
  end
70
96
 
71
- create_table "line_items", force: true do |t|
97
+ create_table "line_items", force: :cascade do |t|
72
98
  t.integer "order_id"
73
99
  t.string "product"
74
100
  end
75
101
 
76
- create_table "orders", force: true do |t|
102
+ create_table "not_on_updates", force: :cascade do |t|
103
+ t.datetime "created_at"
104
+ t.datetime "updated_at"
105
+ end
106
+
107
+ create_table "orders", force: :cascade do |t|
77
108
  t.integer "customer_id"
78
109
  t.string "order_date"
79
110
  end
80
111
 
81
- create_table "people", force: true do |t|
112
+ create_table "people", force: :cascade do |t|
82
113
  t.string "name"
83
114
  t.string "time_zone"
84
115
  end
85
116
 
86
- create_table "post_versions", force: true do |t|
117
+ create_table "post_versions", force: :cascade do |t|
87
118
  t.string "item_type", null: false
88
119
  t.integer "item_id", null: false
89
120
  t.string "event", null: false
@@ -96,31 +127,38 @@ ActiveRecord::Schema.define(version: 20110208155312) do
96
127
 
97
128
  add_index "post_versions", ["item_type", "item_id"], name: "index_post_versions_on_item_type_and_item_id"
98
129
 
99
- create_table "post_with_statuses", force: true do |t|
130
+ create_table "post_with_statuses", force: :cascade do |t|
100
131
  t.integer "status"
101
132
  end
102
133
 
103
- create_table "posts", force: true do |t|
134
+ create_table "posts", force: :cascade do |t|
104
135
  t.string "title"
105
136
  t.string "content"
106
137
  end
107
138
 
108
- create_table "songs", force: true do |t|
139
+ create_table "skippers", force: :cascade do |t|
140
+ t.string "name"
141
+ t.datetime "another_timestamp"
142
+ t.datetime "created_at"
143
+ t.datetime "updated_at"
144
+ end
145
+
146
+ create_table "songs", force: :cascade do |t|
109
147
  t.integer "length"
110
148
  end
111
149
 
112
- create_table "things", force: true do |t|
150
+ create_table "things", force: :cascade do |t|
113
151
  t.string "name"
114
152
  end
115
153
 
116
- create_table "translations", force: true do |t|
154
+ create_table "translations", force: :cascade do |t|
117
155
  t.string "headline"
118
156
  t.string "content"
119
157
  t.string "language_code"
120
158
  t.string "type"
121
159
  end
122
160
 
123
- create_table "version_associations", force: true do |t|
161
+ create_table "version_associations", force: :cascade do |t|
124
162
  t.integer "version_id"
125
163
  t.string "foreign_key_name", null: false
126
164
  t.integer "foreign_key_id"
@@ -129,7 +167,7 @@ ActiveRecord::Schema.define(version: 20110208155312) do
129
167
  add_index "version_associations", ["foreign_key_name", "foreign_key_id"], name: "index_version_associations_on_foreign_key"
130
168
  add_index "version_associations", ["version_id"], name: "index_version_associations_on_version_id"
131
169
 
132
- create_table "versions", force: true do |t|
170
+ create_table "versions", force: :cascade do |t|
133
171
  t.string "item_type", null: false
134
172
  t.integer "item_id", null: false
135
173
  t.string "event", null: false
@@ -149,13 +187,13 @@ ActiveRecord::Schema.define(version: 20110208155312) do
149
187
 
150
188
  add_index "versions", ["item_type", "item_id"], name: "index_versions_on_item_type_and_item_id"
151
189
 
152
- create_table "whatchamajiggers", force: true do |t|
190
+ create_table "whatchamajiggers", force: :cascade do |t|
153
191
  t.string "owner_type"
154
192
  t.integer "owner_id"
155
193
  t.string "name"
156
194
  end
157
195
 
158
- create_table "widgets", force: true do |t|
196
+ create_table "widgets", force: :cascade do |t|
159
197
  t.string "name"
160
198
  t.text "a_text"
161
199
  t.integer "an_integer"
@@ -171,7 +209,7 @@ ActiveRecord::Schema.define(version: 20110208155312) do
171
209
  t.datetime "updated_at"
172
210
  end
173
211
 
174
- create_table "wotsits", force: true do |t|
212
+ create_table "wotsits", force: :cascade do |t|
175
213
  t.integer "widget_id"
176
214
  t.string "name"
177
215
  t.datetime "created_at"