From d5e15f61f3887ae45d0f9fb4acf7de478f175df5 Mon Sep 17 00:00:00 2001 From: Gabriel Sobrinho Date: Sat, 31 Aug 2024 02:28:22 -0300 Subject: [PATCH] Add support for custom version association class with separate database connection (#46) --- CHANGELOG.md | 1 + README.md | 15 +++++++++++++++ .../model_config.rb | 7 +++++++ .../record_trail.rb | 4 ++-- .../reifiers/has_and_belongs_to_many.rb | 2 +- .../reifiers/has_many.rb | 2 +- .../reifiers/has_one.rb | 14 +++++++++----- spec/dummy_app/app/models/custom_version.rb | 5 +++++ .../app/models/custom_version_association.rb | 5 +++++ spec/dummy_app/app/models/wotsit.rb | 2 +- spec/paper_trail/model_config_spec.rb | 19 ++++++++++++++++++- 11 files changed, 65 insertions(+), 11 deletions(-) create mode 100644 spec/dummy_app/app/models/custom_version.rb create mode 100644 spec/dummy_app/app/models/custom_version_association.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index cc69054..cc060d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # CHANGELOG ### Unreleased - [View Diff](https://github.com/westonganger/paper_trail-association_tracking/compare/v2.2.1...master) +- [#46](https://github.com/westonganger/paper_trail-association_tracking/pull/46) - Add support for custom version association class with separate database connection - [#49](https://github.com/westonganger/paper_trail-association_tracking/pull/49) - Fix has_many though associations when the through association is singular - [#48](https://github.com/westonganger/paper_trail-association_tracking/pull/48) - Fix belongs_to polymorphic associations with "empty string" type diff --git a/README.md b/README.md index 3bb9b3f..ce1d9d5 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,21 @@ t.amount # 100 t.location.latitude # 12.345, instead of 54.321 ``` +# Configuration + +You can configure a different version association class by using the following configuration: + +```ruby +class ProductionVersionAssociation < PaperTrail::VersionAssociation + # You can change the table name, i.e.: + self.table_name = "product_version_associations" +end + +class Product < ActiveRecord::Base + has_paper_trail version_associations: { class_name: "ProductVersionAssociation" } +end +``` + # Limitations 1. Only reifies the first level of associations. If you want to include nested associations simply add `:through` relationships to your model. diff --git a/lib/paper_trail_association_tracking/model_config.rb b/lib/paper_trail_association_tracking/model_config.rb index b93a4e7..fe7a5b1 100644 --- a/lib/paper_trail_association_tracking/model_config.rb +++ b/lib/paper_trail_association_tracking/model_config.rb @@ -10,10 +10,17 @@ module ModelConfig def setup(options = {}) super + @model_class.class_attribute :version_association_class_name + @model_class.version_association_class_name = options.dig(:version_associations, :class_name) || "PaperTrail::VersionAssociation" + setup_transaction_callbacks setup_callbacks_for_habtm(options[:join_tables]) end + def version_association_class + @version_association_class ||= @model_class.version_association_class_name.constantize + end + private # Raises an error if the provided class is an `abstract_class`. diff --git a/lib/paper_trail_association_tracking/record_trail.rb b/lib/paper_trail_association_tracking/record_trail.rb index 39ed48e..fbd4af5 100644 --- a/lib/paper_trail_association_tracking/record_trail.rb +++ b/lib/paper_trail_association_tracking/record_trail.rb @@ -133,7 +133,7 @@ def save_habtm_associations(version) @record.class.reflect_on_all_associations(:has_and_belongs_to_many).each do |a| next unless save_habtm_association?(a) habtm_assoc_ids(a).each do |id| - ::PaperTrail::VersionAssociation.create( + @record.class.paper_trail.version_association_class.create( version_id: version.transaction_id, foreign_key_name: a.name, foreign_key_id: id, @@ -180,7 +180,7 @@ def save_bt_association(assoc, version) end if assoc_version_args.key?(:foreign_key_id) - ::PaperTrail::VersionAssociation.create(assoc_version_args) + @record.class.paper_trail.version_association_class.create(assoc_version_args) end end diff --git a/lib/paper_trail_association_tracking/reifiers/has_and_belongs_to_many.rb b/lib/paper_trail_association_tracking/reifiers/has_and_belongs_to_many.rb index 8ed9446..afac0a2 100644 --- a/lib/paper_trail_association_tracking/reifiers/has_and_belongs_to_many.rb +++ b/lib/paper_trail_association_tracking/reifiers/has_and_belongs_to_many.rb @@ -8,7 +8,7 @@ module HasAndBelongsToMany class << self # @api private def reify(pt_enabled, assoc, model, options, transaction_id) - version_ids = ::PaperTrail::VersionAssociation. + version_ids = model.class.paper_trail.version_association_class. where("foreign_key_name = ?", assoc.name). where("version_id = ?", transaction_id). pluck(:foreign_key_id) diff --git a/lib/paper_trail_association_tracking/reifiers/has_many.rb b/lib/paper_trail_association_tracking/reifiers/has_many.rb index 0bc382e..d8a0c0f 100644 --- a/lib/paper_trail_association_tracking/reifiers/has_many.rb +++ b/lib/paper_trail_association_tracking/reifiers/has_many.rb @@ -100,7 +100,7 @@ def load_versions_for_hm_association(assoc, model, version_table, tx_id, version .select { |x| x <= model.class.base_class && x.method_defined?(assoc.name) } .map(&:name) - version_ids = ::PaperTrail::VersionAssociation. + version_ids = model.class.paper_trail.version_association_class. joins(model.class.version_association_name). select("MIN(version_id) as version_id"). where("foreign_key_name = ?", assoc.foreign_key). diff --git a/lib/paper_trail_association_tracking/reifiers/has_one.rb b/lib/paper_trail_association_tracking/reifiers/has_one.rb index dddbe4c..a3f1d01 100644 --- a/lib/paper_trail_association_tracking/reifiers/has_one.rb +++ b/lib/paper_trail_association_tracking/reifiers/has_one.rb @@ -90,13 +90,17 @@ def load_version(assoc, model, transaction_id, version_at) # @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 - model.class.paper_trail.version_class.joins(:version_associations). - where("version_associations.foreign_key_name = ?", assoc.foreign_key). - where("version_associations.foreign_key_id = ?", model.id). + + version_ids = model.class.paper_trail.version_association_class. + joins(model.class.version_association_name). + where("foreign_key_name = ?", assoc.foreign_key). + where("foreign_key_id = ?", model.id). where("#{version_table_name}.item_type = ?", base_class_name). where("created_at >= ? OR transaction_id = ?", version_at, transaction_id). - order("#{version_table_name}.id ASC"). - load + order("version_id ASC"). + pluck("version_id") + + model.class.paper_trail.version_class.find(version_ids) end # @api private diff --git a/spec/dummy_app/app/models/custom_version.rb b/spec/dummy_app/app/models/custom_version.rb new file mode 100644 index 0000000..7dcf432 --- /dev/null +++ b/spec/dummy_app/app/models/custom_version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class CustomVersion < PaperTrail::Version + has_many :version_associations, class_name: "CustomVersionAssociation", foreign_key: :version_id, dependent: :destroy +end diff --git a/spec/dummy_app/app/models/custom_version_association.rb b/spec/dummy_app/app/models/custom_version_association.rb new file mode 100644 index 0000000..44eda39 --- /dev/null +++ b/spec/dummy_app/app/models/custom_version_association.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class CustomVersionAssociation < PaperTrail::VersionAssociation + belongs_to :version, class_name: "CustomVersion", foreign_key: :version_id, optional: true +end diff --git a/spec/dummy_app/app/models/wotsit.rb b/spec/dummy_app/app/models/wotsit.rb index cd4b9ad..0ec1dd2 100644 --- a/spec/dummy_app/app/models/wotsit.rb +++ b/spec/dummy_app/app/models/wotsit.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Wotsit < ActiveRecord::Base - has_paper_trail + has_paper_trail versions: { class_name: "CustomVersion" }, version_associations: { class_name: "CustomVersionAssociation" } belongs_to :widget, optional: true diff --git a/spec/paper_trail/model_config_spec.rb b/spec/paper_trail/model_config_spec.rb index d0cbe09..7f1ac91 100644 --- a/spec/paper_trail/model_config_spec.rb +++ b/spec/paper_trail/model_config_spec.rb @@ -3,6 +3,23 @@ require "spec_helper" module PaperTrail - ::RSpec.describe ModelConfig do + ::RSpec.describe ModelConfig, versioning: true do + after do + Timecop.return + end + + describe "class_name" do + before do + @widget = Widget.create(name: "widget_0") + @wotsit = Wotsit.create(widget_id: @widget.id, name: "wotsit_0") + @version = @wotsit.versions.last + @version_association = @version.version_associations.last + end + + it "customize the version association class" do + expect(@version).to be_a(CustomVersion) + expect(@version_association).to be_a(CustomVersionAssociation) + end + end end end