列出所有paper_trail版本(包括关联)的正确方法是什么?

关于paper_trail gem的问题 。

仅关联更改时,将不会为主模型创建版本记录。 那么列出某个记录的所有版本(包括其关联)的正确方法是什么?

我应该查询这样的事情吗? (不好的一点是这个SQL查询可能是长而低的性能。)

f = "(item_type = 'Place' AND item_id = ?) OR (item_type = 'PlaceName' AND item_id IN (?))" PaperTrail::Version.where(f, @place.id, @place.names.map { |n| n.id }) 

或者我应该在只更改关联时创建版本记录? 我认为@DavidHam尝试了同样的事情并提出了类似的问题,但没有人回答。

所以,我找到了一种方法来做到这一点,但它并不完全漂亮,并且每次更改关联时都不会创建新版本。 但是,它确实为您提供了一种按时间顺序检索版本的有效方法,以便您可以在关联更改之前/之后查看版本的外观。

首先,我为给定该模型的id的asscoiation版本检索所有id:

 def associations_version_ids(item_id=nil) if !item_id.nil? ids = PaperTrail::VersionAssociation.where(foreign_key_id: item_id, foreign_key_name: 'item_id').select(:version_id) return ids else ids = PaperTrail::VersionAssociation.where(foreign_key_name: 'item_id').select(:version_id) return ids end end 

然后我使用此函数中的VersionAssociation ids将所有版本放在一起。 它将返回按时间顺序排列的PaperTrail :: Version。 因此,这些信息对于活动日志等非常有用。通过这种方式将版本及其关联重新组合在一起非常简单:

 def all_versions if !@item_id.nil? association_version_ids = associations_version_ids(@item_id) all_versions = PaperTrail::Version .where("(item_type = ? AND item_id = ?) OR id IN (?)", 'Item', @item_id, association_version_ids) .where("object_changes IS NOT NULL") .order(created_at: :desc) return all_versions else assocation_ids = associations_version_ids all_versions = PaperTrail::Version .where("item_type = ? OR id IN (?)", 'Item', association_ids) .where("object_changes IS NOT NULL") .order(created_at: :desc) return all_versions end end 

同样,不是一个完美的答案,因为每次有变化都没有新版本,但它是可管理的。

这更像是一种方法,而不是一个特定的答案,但这里有。

在我的情况下,我需要一个版本历史记录,这样每当有人改变一个Child ,他们也会在’Parent’上更改一个标志。 但是我需要一种方法来显示一个审计跟踪,它将显示所有子项的初始值,以及每当有人更改子项时父项的审计行。

所以,很简单,它是这样的:

 class Parent < ActiveRecord::Base has_paper_trail has_many :children end class Child < ActiveRecord::Base has_paper_trail belongs_to :parent end 

因此,只要Child上有更改,我们就需要在Parent上创建一个版本。

首先,尝试更改Child ,如下所示:

 class Child < ActiveRecord::Base has_paper_trail belongs_to :parent, touch: true end 

这应该(应该!未经测试)在Child更改时在Parent上创建时间戳。

然后,要获取每个Parent版本的:children的状态,可以在Child的版本中搜索transaction_idParent匹配的版本。

 # loop through the parent versions @parent.versions.each do |version| @parent.children.versions.each do |child| # Then loop through the children and get the version of the Child where the transaction_id matches the given Parent version child_version = child.versions.find_by transaction_id: version.transaction_id if child_version # it will only exist if this Child changed in this Parent's version # do stuff with the child's version end 

这在我的情况下起作用,希望这里的某些内容对你有用。

[更新]

我找到了更好的方法。 您需要更新事务内的关联以使此代码有效。

 class Place < ActiveRecord::Base has_paper_trail before_update :check_update def check_update return if changed_notably? tracking_has_many_associations = [ ... ] tracking_has_has_one_associations = [ ... ] tracking_has_many_associations.each do |a| send(a).each do |r| if r.send(:changed_notably?) || r.marked_for_destruction? self.updated_at = DateTime.now return end end end tracking_has_one_associations.each do |a| r = send(a) if r.send(:changed_notably?) || r.marked_for_destruction? self.updated_at = DateTime.now return end end end end class Version < PaperTrail::Version def associated_versions Version.where(transaction_id: transaction_id) if transaction_id end end 

[原始答案]

这是迄今为止我发现的最佳方式。 (@ JohnSchaum的回答对我很有帮助,谢谢!)

在开始之前,我已将polymorphic_type列添加到versions表中。

 class AddPolymorphicTypeToVersions < ActiveRecord::Migration def change add_column :versions, :polymorphic_type, :string end end 

并设置如下模型:

 # app/models/version.rb class Version < PaperTrail::Version has_many :associations, class_name: 'PaperTrail::VersionAssociation' end # app/models/link.rb class Link < ActiveRecord::Base has_paper_trail meta: { polymorphic_type: :linkable_type } belongs_to :linkable, polymorphic: true end # app/models/place.rb class Place < ActiveRecord::Base has_paper_trail has_many :links, as: :linkable def all_versions f = '(item_type = "Place" AND item_id = ?) OR ' + '(foreign_key_name = "place_id" AND foreign_key_id = ?) OR ' + '(polymorphic_type = "Place" AND foreign_key_id = ?)' Version.includes(:associations).references(:associations).where(f, id, id, id) end end 

我们现在可以获得包括如下关联的版本:

 @place.all_versions.order('created_at DESC')