Skip to content

Commit

Permalink
make the object column optional
Browse files Browse the repository at this point in the history
  • Loading branch information
seanlinsley committed Jul 24, 2018
1 parent ac710b3 commit 63e949e
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 4 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ recommendations of [keepachangelog.com](http://keepachangelog.com/).

### 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

Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

### 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

You may want to turn PaperTrail off to speed up your tests. See [Turning
Expand Down
7 changes: 7 additions & 0 deletions lib/paper_trail/events/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,13 @@ def record_object_changes?
@record.class.paper_trail.version_class.column_names.include?("object_changes")
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
# nascent version record. If the `object` column is a postgres `json`
# column, then a hash can be used in the assignment, otherwise the column
Expand Down
4 changes: 3 additions & 1 deletion lib/paper_trail/events/destroy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ def data
item_id: @record.id,
item_type: @record.class.base_class.name,
event: @record.paper_trail_event || "destroy",
object: recordable_object(false),
whodunnit: PaperTrail.request.whodunnit
}
if record_object?
data[:object] = recordable_object(false)
end
merge_metadata_into(data)
end
end
Expand Down
4 changes: 3 additions & 1 deletion lib/paper_trail/events/update.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ def initialize(record, in_after_callback, is_touch, force_changes)
def data
data = {
event: @record.paper_trail_event || "update",
object: recordable_object(@is_touch),
whodunnit: PaperTrail.request.whodunnit
}
if @record.respond_to?(:updated_at)
data[:created_at] = @record.updated_at
end
if record_object?
data[:object] = recordable_object(@is_touch)
end
if record_object_changes?
data[:object_changes] = recordable_object_changes(@changes)
end
Expand Down
5 changes: 4 additions & 1 deletion lib/paper_trail/queries/versions/where_object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ def initialize(version_model_class, attributes)

# @api private
def execute
case @version_model_class.columns_hash["object"].type
column = @version_model_class.columns_hash["object"]
fail "where_object can't be called without an object column" unless column

case column.type
when :jsonb
jsonb
when :json
Expand Down
3 changes: 3 additions & 0 deletions lib/paper_trail/version_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ def object_deserialized
# - `:preserve` - Attributes undefined in version record are not modified.
#
def reify(options = {})
unless self.class.column_names.include? "object"
fail "reify can't be called without an object column"
end
return nil if object.nil?
::PaperTrail::Reifier.reify(self, options)
end
Expand Down
46 changes: 46 additions & 0 deletions spec/paper_trail/model_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -877,4 +877,50 @@
expect(widget.versions.empty?).to(eq(true))
end
end

context "without the object column" do
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

it "versions are created" do
song = Song.create(length: 4)
version = song.versions.last.attributes
expect(version).to_not include 'object'
expect(version).to match hash_including 'event' => 'create', 'object_changes' => start_with('---')

song.update length: 5
version = song.versions.last.attributes
expect(version).to_not include 'object'
expect(version).to match hash_including 'event' => 'update', 'object_changes' => start_with('---')

song.destroy
version = song.versions.last.attributes
expect(version).to_not include 'object'
expect(version).to match hash_including 'event' => 'destroy', 'object_changes' => 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

0 comments on commit 63e949e

Please sign in to comment.