1
0
Fork 0
mirror of https://github.com/paper-trail-gem/paper_trail.git synced 2022-11-09 11:33:19 -05:00

Merge pull request #1062 from airblade/various_2018-03-11

Various 2018-03-11
This commit is contained in:
Jared Beck 2018-03-11 03:44:51 -04:00 committed by GitHub
commit 87f097c05f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 79 additions and 20 deletions

View file

@ -12,7 +12,6 @@ recommendations of [keepachangelog.com](http://keepachangelog.com/).
- PaperTrail now uses `frozen_string_literal`, so you should assume that all - PaperTrail now uses `frozen_string_literal`, so you should assume that all
strings it returns are frozen. strings it returns are frozen.
- Using `where_object_changes` to read YAML from a text column will now raise - 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. error, was deprecated in 8.1.0.
### Breaking Changes, Minor ### Breaking Changes, Minor
@ -44,11 +43,17 @@ recommendations of [keepachangelog.com](http://keepachangelog.com/).
### Fixed ### 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 - [#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 where `touch_with_version` saved less data than expected, but only when the
update callback was not installed, eg. `has_paper_trail(on: [])` update callback was not installed, eg. `has_paper_trail(on: [])`
- [#1042](https://github.com/airblade/paper_trail/issues/1042) - A rare issue - [#1042](https://github.com/airblade/paper_trail/issues/1042) - A rare issue
with load order when using PT outside of rails 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) ## 8.1.2 (2017-12-22)

View file

@ -805,8 +805,8 @@ string, please try the [paper_trail-globalid][37] gem.
### 4.b. Associations ### 4.b. Associations
**Experimental feature**, not recommended for production. See known issues **Experimental feature with many known issues. Not recommended for production.**
below. See known issues below.
PaperTrail can restore three types of associations: Has-One, Has-Many, and 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: Has-Many-Through. In order to do this, you will need to do two things:
@ -913,6 +913,8 @@ Associations are an **experimental feature** and have the following known
issues, in order of descending importance. issues, in order of descending importance.
1. PaperTrail only reifies the first level of associations. 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) - 1. [#542](https://github.com/airblade/paper_trail/issues/542) -
Not compatible with [transactional tests][34], aka. transactional fixtures. Not compatible with [transactional tests][34], aka. transactional fixtures.
1. Requires database timestamp columns with fractional second precision. 1. Requires database timestamp columns with fractional second precision.

View file

@ -5,10 +5,42 @@ module PaperTrail
# Reify a single `has_one` association of `model`. # Reify a single `has_one` association of `model`.
# @api private # @api private
module HasOne 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 class << self
# @api private # @api private
def reify(assoc, model, options, transaction_id) 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 return unless version
if version.event == "create" if version.event == "create"
create_event(assoc, model, options) create_event(assoc, model, options)
@ -33,15 +65,29 @@ module PaperTrail
# Given a has-one association `assoc` on `model`, return the version # Given a has-one association `assoc` on `model`, return the version
# record from the point in time identified by `transaction_id` or `version_at`. # record from the point in time identified by `transaction_id` or `version_at`.
# @api private # @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 version_table_name = model.class.paper_trail.version_class.table_name
model.class.paper_trail.version_class.joins(:version_associations). model.class.paper_trail.version_class.joins(:version_associations).
where("version_associations.foreign_key_name = ?", assoc.foreign_key). where("version_associations.foreign_key_name = ?", assoc.foreign_key).
where("version_associations.foreign_key_id = ?", model.id). 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). where("created_at >= ? OR transaction_id = ?", version_at, transaction_id).
order("#{version_table_name}.id ASC"). order("#{version_table_name}.id ASC").
first load
end end
# @api private # @api private

View file

@ -174,14 +174,6 @@ RSpec.describe Article, type: :model, versioning: true do
).to(eq("Some text here.")) ).to(eq("Some text here."))
end end
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 end
context "#destroy" do context "#destroy" do
@ -193,4 +185,13 @@ RSpec.describe Article, type: :model, versioning: true do
expect(article.versions.map(&:event)).to(match_array(%w[create destroy])) expect(article.versions.map(&:event)).to(match_array(%w[create destroy]))
end end
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 end

View file

@ -8,7 +8,7 @@ RSpec.describe Person, type: :model, versioning: true do
end end
describe "#cars and bicycles" do describe "#cars and bicycles" do
it "can be reified", skip: "Known Issue #594" do it "can be reified" do
person = Person.create(name: "Frank") person = Person.create(name: "Frank")
car = Car.create(name: "BMW 325") car = Car.create(name: "BMW 325")
bicycle = Bicycle.create(name: "BMX 1.0") bicycle = Bicycle.create(name: "BMX 1.0")
@ -23,11 +23,16 @@ RSpec.describe Person, type: :model, versioning: true do
expect(person.reload.versions.length).to(eq(3)) 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 # See https://github.com/airblade/paper_trail/issues/594
second_version = person.reload.versions.second.reify(has_one: true) expect {
expect(second_version.car.name).to(eq("BMW 325")) person.reload.versions.second.reify(has_one: true)
expect(second_version.bicycle.name).to(eq("BMX 1.0")) }.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 end
end end