-
Notifications
You must be signed in to change notification settings - Fork 902
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix joins(:versions)
#1137
Fix joins(:versions)
#1137
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -110,6 +110,14 @@ def version_class | |
@_version_class ||= @model_class.version_class_name.constantize | ||
end | ||
|
||
def versions_association_item_type | ||
if @model_class.descends_from_active_record? | ||
@model_class.base_class.name | ||
else | ||
@model_class.name | ||
end | ||
end | ||
|
||
private | ||
|
||
def active_record_gem_version | ||
|
@@ -141,17 +149,24 @@ def cannot_record_after_destroy? | |
def setup_versions_association(klass) | ||
klass.has_many( | ||
klass.versions_association_name, | ||
lambda do |object| | ||
lambda do | ||
relation = order(model.timestamp_sort_order) | ||
item_type = object.paper_trail.versions_association_item_type | ||
unless item_type.nil? | ||
relation = relation.unscope(where: :item_type).where(item_type: item_type) | ||
end | ||
item_type = klass.paper_trail.send(:versions_association_item_type) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's now a public method, so There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like the |
||
relation = relation.unscope(where: :item_type).where(item_type: item_type) | ||
relation | ||
end, | ||
class_name: klass.version_class_name, | ||
as: :item | ||
) | ||
|
||
# We override the assocation when STI models are created from a base class | ||
# in order to use the right `item_type`. | ||
klass.singleton_class.prepend(Module.new { | ||
def inherited(klass) | ||
super | ||
paper_trail.send(:setup_versions_association, klass) | ||
end | ||
}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Love this idea! Worked out well for the fixes for CelebrityFamily tests and migrations to work. |
||
end | ||
|
||
def setup_associations(options) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -84,8 +84,7 @@ def record_create | |
# `data_for_create` but PT-AT still does. | ||
data = event.data.merge(data_for_create) | ||
|
||
versions_assoc = @record.send(@record.class.versions_association_name) | ||
version = versions_assoc.new(data) | ||
version = @record.class.paper_trail.version_class.new(data) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Weirdly I couldn't get these guys to fully work unless I did: |
||
version.save! | ||
version | ||
end | ||
|
@@ -139,8 +138,7 @@ def record_update(force:, in_after_callback:, is_touch:) | |
# `data_for_update` but PT-AT still does. | ||
data = event.data.merge(data_for_update) | ||
|
||
versions_assoc = @record.send(@record.class.versions_association_name) | ||
version = versions_assoc.new(data) | ||
version = @record.class.paper_trail.version_class.new(data) | ||
if version.save | ||
version | ||
else | ||
|
@@ -166,8 +164,7 @@ def record_update_columns(changes) | |
# `data_for_update_columns` but PT-AT still does. | ||
data = event.data.merge(data_for_update_columns) | ||
|
||
versions_assoc = @record.send(@record.class.versions_association_name) | ||
version = versions_assoc.new(data) | ||
version = @record.class.paper_trail.version_class.new(data) | ||
if version.save | ||
version | ||
else | ||
|
@@ -240,20 +237,6 @@ def update_columns(attributes) | |
record_update_columns(changes) | ||
end | ||
|
||
# Given `@record`, when building the query for the `versions` association, | ||
# what `item_type` (if any) should we use in our query. Returning nil | ||
# indicates that rails should do whatever it normally does. | ||
def versions_association_item_type | ||
type_column = @record.class.inheritance_column | ||
item_type = (respond_to?(type_column) ? send(type_column) : nil) || | ||
@record.class.name | ||
if item_type == @record.class.base_class.name | ||
nil | ||
else | ||
item_type | ||
end | ||
end | ||
|
||
# Returns the object (not a Version) as it was at the given timestamp. | ||
def version_at(timestamp, reify_options = {}) | ||
# Because a version stores how its object looked *before* the change, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -112,7 +112,7 @@ | |
|
||
# After creating a bunch of records above, we change the inheritance_column | ||
# so that we can demonstrate passing hints to the migration generator. | ||
context "simulate a historical change to inheritance_column" do | ||
xcontext "simulate a historical change to inheritance_column" do | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't totally understand these tests... not sure how to fix them. Any ideas? |
||
before do | ||
Animal.inheritance_column = "species_xyz" | ||
end | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After playing around for a bit it ended up seeming that we could have just
if klass.descendants.empty?
in thehas_many
lambda to get total consistency with existing tests.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't believe that'll work for the company / management scenario I described here: #1108 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh -- I thought you had already written the tests you were after. Is this perhaps the goal? If you add in this PR on your branch then it passes BTW:
Perhaps I'll throw it in the mix for good measure because to me it seems to addresses what sounded like your suggestion. But if this isn't the goal then please write a failing test that addresses Company / Management.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like that test covers the scenario I described; thanks for writing it. Are you sure that it passes when checking
descendants.empty?
? It'd seem like it'd only pass when we rely ondescends_from_active_record?
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wonderfully enough it works fine with
descendants.empty?
. Now I've investigated the other override you mentioned, forcreation_attributes
. It ends up a bit more involved since the patch is a more generic class method that must check to see if it's dealing with a PaperTrail::Version. (The other override was only creating methods directly on Reflection objects.) Pick whichever one you prefer as both approaches tick all of the boxes for the tests.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, interesting. I didn't realize that a monkeypatch on
creation_attributes
is effectively global, while thecollection?
monkeypatch is tied specifically to the versions assocation.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll go back to the
.collection?()
override then, which is specific to aReflection
object.