Skip to content

Reify on associations fails if using Single Table Inheritance #594

Description

@ksornberger

It appears as though if Single Table Inheritance is being used on an association, if you try to reify with has_many: true or has_one: true, it will not find and build the previous version of the association and instead always use the current version of the association when browsing previous versions.

I believe this is happening because if STI is used, the item_type is always stored as the base class. But when calling the method reify_has_many_directly, it is using the main class of the association. This builds a WHERE clause that is looking for the wrong value in the item_type column.

ex:

class Document < ActiveRecord::Base
  has_paper_trail
  has_one :authorship
end

class Assignment < ActiveRecord::Base
  belongs_to :document 
end

class Authorship < Assignment
  has_paper_trail
end

@document.reify(has_many: true, has_one: true)

The last line there will produce a SQL query like this:

SELECT  `versions`.* FROM `versions` 
INNER JOIN `version_associations` ON `version_associations`.`version_id` = `versions`.`id` 
WHERE (version_associations.foreign_key_name = 'document_id') 
AND (version_associations.foreign_key_id = 1) 
AND (versions.item_type = 'Authorship') 
AND (created_at >= '2015-08-26 20:07:28.000000' OR transaction_id = 933)  
ORDER BY versions.id ASC LIMIT 1

But item_type will never be 'Authorship', it is always stored as Assignment. I'm still working on figuring out a solution to this if I can, but this seems to be what is happening from my understanding.

Modifying the database manually and changing the item_type column from Assignment to Authorship results in being able to view the correct versions of the association as I browse through the document history.

Activity

  1. jaredbeck commented on Sep 8, 2015

    @jaredbeck
    Member

    Sounds like you're onto something. Thanks for the bug report.

    I'm still working on figuring out a solution to this ..

    Any luck? Even a failing test would be welcome, thanks.

  2. jaredbeck commented on Sep 30, 2015

    @jaredbeck
    Member

    Still working on this, Kevin? Were you able to write a failing test? Thanks.

  3. ksornberger commented on Oct 1, 2015

    @ksornberger
    Author

    Hey, sorry.
    I'm still planning on looping back to take another look at this, just haven't had the time to get my head into the right space to try to sort this out again. I'll try to make it a priority soon and keep you updated!

  4. jaredbeck commented on Dec 2, 2015

    @jaredbeck
    Member

    I recently adapted the AR bug report template for use in PaperTrail. Maybe it will help you write your failing test? Please check it out: https://github.com/airblade/paper_trail/blob/master/doc/bug_report_template.rb

    I hope it helps!

  5. jaredbeck commented on Jan 8, 2016

    @jaredbeck
    Member

    Kevin, I think I've reproduced your issue: https://gist.github.com/jaredbeck/4664e45abe3aa09416ae

    Does that look like the issue you're seeing?

  6. daneshd commented on Jan 8, 2016

    @daneshd

    I worked with Kevin on this, your gist does reproduce the issue. Here's another one too:

    https://gist.github.com/daneshd/f0e61744075e1617dbcb

    I was working on a fix for this issue but I haven't had the time to finish it. One thing I noticed in your report is you'd like the item_type to be Authorship. I went down that path when patching paper_trail but it didn't work out. I eventually found this

    Using polymorphic associations in combination with single table inheritance (STI) is a little tricky. In order for the associations to work as expected, ensure that you store the base model for the STI models in the type column of the polymorphic association.

    Saving item_type to the child model instead of the base model caused issues with how it was loaded.

    I tried to change the way the lookup was done to grab all the versions whose class is the base model here. I only started on the reify_has_ones.

    - where("#{version_table_name}.item_type = ?", assoc.class_name).
    + where("#{version_table_name}.item_type = ?", assoc.klass.base_class.name).

    This isn't enough though. You could have more than 1 record saved with the base class if your model uses other has_one associations of the same STI base model (e.g. the sponsorship model in my bug report). Say I have a user that has an authorship and a sponsorship, then there would be 2 version records whose base class is Assignment and whose foreign key is my user's id.

    I tried iterating through the found versions to lookup and filter these by their type. I wasn't sure about this approach because I had to force PT to never skip/ignore the type attributes, and it meant serializing the object data to figure out which to use.

    Our implementation for versioning things caused some other issues for me so I had to put this fix on hold to figure that out. I never got around to reify_has_manys.

  7. added a commit that references this issue on May 4, 2016
  8. jaredbeck commented on May 4, 2016

    @jaredbeck
    Member

    This just came up again recently. What do you think about ecd1df7 as a recommendation?

  9. jaredbeck commented on May 4, 2016

    @jaredbeck
    Member

    What do you think about ecd1df7 as a recommendation?

    Nevermind, I forgot about 23ffbdc. Also, I don't think ecd1df7 would help with reifying associations, would it?

  10. daneshd commented on May 6, 2016

    @daneshd

    The STI related documentation from ecd1df7 looks good to me. Reifying the polymorphic associations are currently bugging out though. I think it may be better to say that it's a known issue instead. What do you think?

  11. jaredbeck commented on May 6, 2016

    @jaredbeck
    Member

    I think it may be better to say that it's a known issue instead.

    https://github.com/airblade/paper_trail#5a-single-table-inheritance-sti now mentions this issue (#594) as a known issue.

  12. added a commit that references this issue on May 9, 2016
  13. 12 remaining items

  14. andre1810 commented on Dec 18, 2017

    @andre1810
    Contributor

    @daneshd that is the only solution without adding a item_sub_type column filled if item is not a base class. This column would only be used for version lookup.

  15. andre1810 commented on Dec 20, 2017

    @andre1810
    Contributor

    @jaredbeck I need this feature working for versioning my models correctly as soon as possible. I found that changing the class name on reification to the base class name fixes my issue. I changed that and opened an PR. This will not fix the reification issues mentioned by @daneshd on having multiple has_one associations on the same model pointing to a polymorphic model but has_many_through associations to polymorphic models.

  16. jaredbeck commented on Dec 22, 2017

    @jaredbeck
    Member

    Thanks to André's work in #1028 this issue is partially fixed and released as 8.1.2. Also thanks to André, we have a failing (skipped) test in person_spec.rb that should demonstrate the remaining issue.

  17. jaredbeck commented on Mar 11, 2018

    @jaredbeck
    Member

    Also thanks to André, we have a failing (skipped) test in person_spec.rb that should demonstrate the remaining issue.

    Closed by 06a5e30 (will release in 9.0.0) which improves the message of the error raised. Because it's a very rare issue on an experimental feature, I don't intended to work on it further (thus, closing this) but PRs are welcome.

  18. added 4 commits that reference this issue on Jun 5, 2018
  19. added 3 commits that reference this issue on Jul 23, 2018
  20. added a commit that references this issue on Jul 30, 2018
  21. added a commit that references this issue on Dec 14, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions