-
Notifications
You must be signed in to change notification settings - Fork 0
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
Make STI .joins() fix more consistent with existing tests #1
base: sti-join-bug
Are you sure you want to change the base?
Changes from 7 commits
b7a1dcf
f561e64
7489c3f
a8583c3
85b956b
cefac8b
7372b8f
7ce28d8
b91ae7a
dd5eab9
cd8a5ca
ad549eb
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,14 +110,6 @@ 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 | ||
|
@@ -147,20 +139,31 @@ def cannot_record_after_destroy? | |
# is "Dog". If `attrs["species"]` is blank, `item_type` is "Animal". See | ||
# `spec/models/animal_spec.rb`. | ||
def setup_versions_association(klass) | ||
klass.has_many( | ||
has_manys = klass.has_many( | ||
klass.versions_association_name, | ||
lambda do | ||
relation = order(model.timestamp_sort_order) | ||
item_type = klass.paper_trail.send(:versions_association_item_type) | ||
relation = relation.unscope(where: :item_type).where(item_type: item_type) | ||
relation | ||
order!(model.timestamp_sort_order) | ||
unscope(where: :item_type).where(item_type: klass.name) unless klass.descendants.any? | ||
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`. | ||
# Only for this .versions association override HasManyAssociation#collection? | ||
# (that normally always returns true) so it returns false when referring to | ||
# a subclassed model that uses STI. Allows .create() events not to revert | ||
# back to base_class at the final stages when Association#creation_attributes | ||
# gets called. | ||
has_manys[klass.versions_association_name.to_s].define_singleton_method(:collection?) do | ||
active_record.descends_from_active_record? | ||
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. How confident can we be that 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. How often does BTW, when monkeypatching code I like to add a link to the version-specific lines of code like this: https://github.com/rails/rails/blob/v5.2.1/activerecord/lib/active_record/associations/association.rb#L198-L210 Since has_manys[klass.versions_association_name.to_s].singleton_class.prepend(Module.new {
def creation_attributes
if active_record.descends_from_active_record?
super # sets `item_type` and `item_id`
else
{} # we set these elsewhere. Rails would incorrectly set them to the STI base class.
end
end
}) That raises the question: why don't we always pass in the correct 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. CC @jaredbeck 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 been used in this way since Rails v4.0, and before that a very similar test was used, albeit one that wouldn't work out with our override:
At first I had hoped to have a solution that utilised this approach ... but it requires a little more code. The only way I see it working is as a class method added to the HasManyAssociation class, and inside a test to see if we're dealing with a PaperTrail::Version. For fun I've put that together in the latest commit. 10 lines of stuff as opposed to this little 4-liner. I'm certainly OK with having this either way -- both approaches establish the same net result.
It's very specific just to PaperTrail::Version objects, and only has effect for anything subclassed. 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. Re: paper-trail-gem#1137 (comment) Are we okay with globally patching 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. Good points on |
||
end | ||
|
||
setup_versions_association_when_inheriting(klass) | ||
end | ||
|
||
# When STI models are created from a base class, override the otherwise-inherited | ||
# has_many :versions in order to use the right `item_type`. | ||
def setup_versions_association_when_inheriting(klass) | ||
klass.singleton_class.prepend(Module.new { | ||
def inherited(klass) | ||
super | ||
|
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.
order!
is tagged:nodoc:
meaning that it is private API. The rails team could remove it at any time without warning. I don't think we should use it.