make the object column optional
This commit is contained in:
parent
ac710b3197
commit
68ecf779da
|
@ -11,7 +11,9 @@ recommendations of [keepachangelog.com](http://keepachangelog.com/).
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- None
|
- [#1099](https://github.com/paper-trail-gem/paper_trail/issues/1099) -
|
||||||
|
Ability to save ~50% storage space by making the `object` column optional.
|
||||||
|
Note that this disables `reify` and `where_object`.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|
|
@ -1212,6 +1212,12 @@ A valid adapter is a class that contains the following methods:
|
||||||
|
|
||||||
For an example of such an implementation, see [paper_trail-hashdiff](https://github.com/hashwin/paper_trail-hashdiff)
|
For an example of such an implementation, see [paper_trail-hashdiff](https://github.com/hashwin/paper_trail-hashdiff)
|
||||||
|
|
||||||
|
### 6.d. Excluding the Object Column
|
||||||
|
|
||||||
|
The `object` column ends up storing a lot of duplicate data if you have models that have many columns,
|
||||||
|
and that are updated many times. You can save ~50% of storage space by removing the column from the
|
||||||
|
versions table. It's important to note that this will disable `reify` and `where_object`.
|
||||||
|
|
||||||
## 7. Testing
|
## 7. Testing
|
||||||
|
|
||||||
You may want to turn PaperTrail off to speed up your tests. See [Turning
|
You may want to turn PaperTrail off to speed up your tests. See [Turning
|
||||||
|
|
|
@ -254,6 +254,13 @@ module PaperTrail
|
||||||
@record.class.paper_trail.version_class.column_names.include?("object_changes")
|
@record.class.paper_trail.version_class.column_names.include?("object_changes")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns a boolean indicating whether to store the original object during save.
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
def record_object?
|
||||||
|
@record.class.paper_trail.version_class.column_names.include?("object")
|
||||||
|
end
|
||||||
|
|
||||||
# Returns an object which can be assigned to the `object` attribute of a
|
# Returns an object which can be assigned to the `object` attribute of a
|
||||||
# nascent version record. If the `object` column is a postgres `json`
|
# nascent version record. If the `object` column is a postgres `json`
|
||||||
# column, then a hash can be used in the assignment, otherwise the column
|
# column, then a hash can be used in the assignment, otherwise the column
|
||||||
|
|
|
@ -16,9 +16,11 @@ module PaperTrail
|
||||||
item_id: @record.id,
|
item_id: @record.id,
|
||||||
item_type: @record.class.base_class.name,
|
item_type: @record.class.base_class.name,
|
||||||
event: @record.paper_trail_event || "destroy",
|
event: @record.paper_trail_event || "destroy",
|
||||||
object: recordable_object(false),
|
|
||||||
whodunnit: PaperTrail.request.whodunnit
|
whodunnit: PaperTrail.request.whodunnit
|
||||||
}
|
}
|
||||||
|
if record_object?
|
||||||
|
data[:object] = recordable_object(false)
|
||||||
|
end
|
||||||
merge_metadata_into(data)
|
merge_metadata_into(data)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,12 +27,14 @@ module PaperTrail
|
||||||
def data
|
def data
|
||||||
data = {
|
data = {
|
||||||
event: @record.paper_trail_event || "update",
|
event: @record.paper_trail_event || "update",
|
||||||
object: recordable_object(@is_touch),
|
|
||||||
whodunnit: PaperTrail.request.whodunnit
|
whodunnit: PaperTrail.request.whodunnit
|
||||||
}
|
}
|
||||||
if @record.respond_to?(:updated_at)
|
if @record.respond_to?(:updated_at)
|
||||||
data[:created_at] = @record.updated_at
|
data[:created_at] = @record.updated_at
|
||||||
end
|
end
|
||||||
|
if record_object?
|
||||||
|
data[:object] = recordable_object(@is_touch)
|
||||||
|
end
|
||||||
if record_object_changes?
|
if record_object_changes?
|
||||||
data[:object_changes] = recordable_object_changes(@changes)
|
data[:object_changes] = recordable_object_changes(@changes)
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,7 +18,10 @@ module PaperTrail
|
||||||
|
|
||||||
# @api private
|
# @api private
|
||||||
def execute
|
def execute
|
||||||
case @version_model_class.columns_hash["object"].type
|
column = @version_model_class.columns_hash["object"]
|
||||||
|
raise "where_object can't be called without an object column" unless column
|
||||||
|
|
||||||
|
case column.type
|
||||||
when :jsonb
|
when :jsonb
|
||||||
jsonb
|
jsonb
|
||||||
when :json
|
when :json
|
||||||
|
|
|
@ -205,6 +205,9 @@ module PaperTrail
|
||||||
# - `:preserve` - Attributes undefined in version record are not modified.
|
# - `:preserve` - Attributes undefined in version record are not modified.
|
||||||
#
|
#
|
||||||
def reify(options = {})
|
def reify(options = {})
|
||||||
|
unless self.class.column_names.include? "object"
|
||||||
|
raise "reify can't be called without an object column"
|
||||||
|
end
|
||||||
return nil if object.nil?
|
return nil if object.nil?
|
||||||
::PaperTrail::Reifier.reify(self, options)
|
::PaperTrail::Reifier.reify(self, options)
|
||||||
end
|
end
|
||||||
|
|
|
@ -877,4 +877,55 @@ RSpec.describe(::PaperTrail, versioning: true) do
|
||||||
expect(widget.versions.empty?).to(eq(true))
|
expect(widget.versions.empty?).to(eq(true))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "without the object column" do
|
||||||
|
# rubocop:disable RSpec/BeforeAfterAll
|
||||||
|
before :all do
|
||||||
|
ActiveRecord::Migration.remove_column :versions, :object
|
||||||
|
PaperTrail::Version.reset_column_information
|
||||||
|
end
|
||||||
|
after :all do
|
||||||
|
ActiveRecord::Migration.add_column :versions, :object, :text
|
||||||
|
PaperTrail::Version.reset_column_information
|
||||||
|
end
|
||||||
|
# rubocop:enable RSpec/BeforeAfterAll
|
||||||
|
|
||||||
|
it "versions are created" do
|
||||||
|
song = Song.create length: 4
|
||||||
|
version = song.versions.last.attributes
|
||||||
|
expect(version).not_to include "object"
|
||||||
|
expect(version["event"]).to eq "create"
|
||||||
|
expect(version["object_changes"]).to start_with("---")
|
||||||
|
|
||||||
|
song.update length: 5
|
||||||
|
version = song.versions.last.attributes
|
||||||
|
expect(version).not_to include "object"
|
||||||
|
expect(version["event"]).to eq "update"
|
||||||
|
expect(version["object_changes"]).to start_with("---")
|
||||||
|
|
||||||
|
song.destroy
|
||||||
|
version = song.versions.last.attributes
|
||||||
|
expect(version).not_to include "object"
|
||||||
|
expect(version["event"]).to eq "destroy"
|
||||||
|
expect(version["object_changes"]).to eq nil
|
||||||
|
end
|
||||||
|
|
||||||
|
it "reify doesn't work" do
|
||||||
|
song = Song.create length: 4
|
||||||
|
song.update length: 5
|
||||||
|
|
||||||
|
expect do
|
||||||
|
song.versions.first.reify
|
||||||
|
end.to raise_error "reify can't be called without an object column"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "where_object doesn't work" do
|
||||||
|
song = Song.create length: 4
|
||||||
|
song.update length: 5
|
||||||
|
|
||||||
|
expect do
|
||||||
|
song.versions.where_object length: 4
|
||||||
|
end.to raise_error "where_object can't be called without an object column"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue