Skip to content

Commit

Permalink
Merge pull request #1062 from airblade/various_2018-03-11
Browse files Browse the repository at this point in the history
Various 2018-03-11
  • Loading branch information
jaredbeck authored Mar 11, 2018
2 parents bd52be1 + 06a5e30 commit 87f097c
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 20 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ recommendations of [keepachangelog.com](http://keepachangelog.com/).
- PaperTrail now uses `frozen_string_literal`, so you should assume that all
strings it returns are frozen.
- Using `where_object_changes` to read YAML from a text column will now raise
- [#1051](https://github.com/airblade/paper_trail/issues/1051) Fix `touch_with_version` does not work with conditional options
error, was deprecated in 8.1.0.

### Breaking Changes, Minor
Expand Down Expand Up @@ -44,11 +43,17 @@ recommendations of [keepachangelog.com](http://keepachangelog.com/).

### Fixed

- [#1051](https://github.com/airblade/paper_trail/issues/1051) - `touch_with_version`
should always create a version, regardles of the `:only` option
- [#1047](https://github.com/airblade/paper_trail/issues/1047) - A rare issue
where `touch_with_version` saved less data than expected, but only when the
update callback was not installed, eg. `has_paper_trail(on: [])`
- [#1042](https://github.com/airblade/paper_trail/issues/1042) - A rare issue
with load order when using PT outside of rails
- [#594](https://github.com/airblade/paper_trail/issues/594) - Improved the
error message for a very rare issue in the experimentatl association tracking
feature involving two has_one associations, referencing STI models with the
same base class, and the same foreign_key.

## 8.1.2 (2017-12-22)

Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -805,8 +805,8 @@ string, please try the [paper_trail-globalid][37] gem.

### 4.b. Associations

**Experimental feature**, not recommended for production. See known issues
below.
**Experimental feature with many known issues. Not recommended for production.**
See known issues below.

PaperTrail can restore three types of associations: Has-One, Has-Many, and
Has-Many-Through. In order to do this, you will need to do two things:
Expand Down Expand Up @@ -913,6 +913,8 @@ Associations are an **experimental feature** and have the following known
issues, in order of descending importance.

1. PaperTrail only reifies the first level of associations.
1. Does not fully support STI (For example, see `spec/models/person_spec.rb` and
`PaperTrail::Reifiers::HasOne::FoundMoreThanOne` error)
1. [#542](https://github.com/airblade/paper_trail/issues/542) -
Not compatible with [transactional tests][34], aka. transactional fixtures.
1. Requires database timestamp columns with fractional second precision.
Expand Down
54 changes: 50 additions & 4 deletions lib/paper_trail/reifiers/has_one.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,42 @@ module Reifiers
# Reify a single `has_one` association of `model`.
# @api private
module HasOne
# A more helpful error message, instead of the AssociationTypeMismatch
# you would get if, eg. we were to try to assign a Bicycle to the :car
# association (before, if there were multiple records we would just take
# the first and hope for the best).
# @api private
class FoundMoreThanOne < RuntimeError
MESSAGE_FMT = <<~STR
Unable to reify has_one association. Expected to find one %s,
but found %d.
This is a known issue, and a good example of why association tracking
is an experimental feature that should not be used in production.
That said, this is a rare error. In spec/models/person_spec.rb we
reproduce it by having two STI models with the same foreign_key (Car
and Bicycle are both Vehicles and the FK for both is owner_id)
If you'd like to help fix this error, please read
https://github.com/airblade/paper_trail/issues/594
and see spec/models/person_spec.rb
STR

def initialize(base_class_name, num_records_found)
@base_class_name = base_class_name.to_s
@num_records_found = num_records_found.to_i
end

def message
format(MESSAGE_FMT, @base_class_name, @num_records_found)
end
end

class << self
# @api private
def reify(assoc, model, options, transaction_id)
version = load_version_for_has_one(assoc, model, transaction_id, options[:version_at])
version = load_version(assoc, model, transaction_id, options[:version_at])
return unless version
if version.event == "create"
create_event(assoc, model, options)
Expand All @@ -33,15 +65,29 @@ def create_event(assoc, model, options)
# Given a has-one association `assoc` on `model`, return the version
# record from the point in time identified by `transaction_id` or `version_at`.
# @api private
def load_version_for_has_one(assoc, model, transaction_id, version_at)
def load_version(assoc, model, transaction_id, version_at)
base_class_name = assoc.klass.base_class.name
versions = load_versions(assoc, model, transaction_id, version_at, base_class_name)
case versions.length
when 0
nil
when 1
versions.first
else
raise FoundMoreThanOne.new(base_class_name, versions.length)
end
end

# @api private
def load_versions(assoc, model, transaction_id, version_at, base_class_name)
version_table_name = model.class.paper_trail.version_class.table_name
model.class.paper_trail.version_class.joins(:version_associations).
where("version_associations.foreign_key_name = ?", assoc.foreign_key).
where("version_associations.foreign_key_id = ?", model.id).
where("#{version_table_name}.item_type = ?", assoc.klass.base_class.name).
where("#{version_table_name}.item_type = ?", base_class_name).
where("created_at >= ? OR transaction_id = ?", version_at, transaction_id).
order("#{version_table_name}.id ASC").
first
load
end

# @api private
Expand Down
17 changes: 9 additions & 8 deletions spec/models/article_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -174,14 +174,6 @@
).to(eq("Some text here."))
end
end

it "creates a version with touch_with_version & :only option combined" do
article = described_class.create

expect { article.paper_trail.touch_with_version }.to change {
PaperTrail::Version.count
}.by(+1)
end
end

context "#destroy" do
Expand All @@ -193,4 +185,13 @@
expect(article.versions.map(&:event)).to(match_array(%w[create destroy]))
end
end

describe "#touch_with_version" do
it "creates a version, ignoring the :only option" do
article = described_class.create
expect { article.paper_trail.touch_with_version }.to change {
::PaperTrail::Version.count
}.by(+1)
end
end
end
15 changes: 10 additions & 5 deletions spec/models/person_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
end

describe "#cars and bicycles" do
it "can be reified", skip: "Known Issue #594" do
it "can be reified" do
person = Person.create(name: "Frank")
car = Car.create(name: "BMW 325")
bicycle = Bicycle.create(name: "BMX 1.0")
Expand All @@ -23,11 +23,16 @@

expect(person.reload.versions.length).to(eq(3))

# Will fail because the correct sub type of the STI model is not present at query.
# See https://github.com/airblade/paper_trail/issues/594
second_version = person.reload.versions.second.reify(has_one: true)
expect(second_version.car.name).to(eq("BMW 325"))
expect(second_version.bicycle.name).to(eq("BMX 1.0"))
expect {
person.reload.versions.second.reify(has_one: true)
}.to(
raise_error(::PaperTrail::Reifiers::HasOne::FoundMoreThanOne) do |err|
expect(err.message.squish).to match(
/Expected to find one Vehicle, but found 2/
)
end
)
end
end
end

0 comments on commit 87f097c

Please sign in to comment.