hoardable 0.14.2 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,47 +1,46 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rails/generators'
3
+ require "rails/generators"
4
4
 
5
5
  module Hoardable
6
6
  # Generates an initializer file for {Hoardable} configuration and a migration with a PostgreSQL
7
7
  # function.
8
8
  class InstallGenerator < Rails::Generators::Base
9
- source_root File.expand_path('templates', __dir__)
9
+ source_root File.expand_path("templates", __dir__)
10
10
  include Rails::Generators::Migration
11
- delegate :supports_schema_enums?, to: :class
12
11
 
13
12
  def create_initializer_file
14
- create_file(
15
- 'config/initializers/hoardable.rb',
16
- <<~TEXT
17
- # Hoardable configuration defaults are below. Learn more at https://github.com/waymondo/hoardable#configuration
18
- #
19
- # Hoardable.enabled = true
20
- # Hoardable.version_updates = true
21
- # Hoardable.save_trash = true
22
- TEXT
23
- )
24
- end
25
-
26
- def change_schema_format_to_sql
27
- return if supports_schema_enums?
28
-
29
- application 'config.active_record.schema_format = :sql'
13
+ create_file("config/initializers/hoardable.rb", <<~TEXT)
14
+ # Hoardable configuration defaults are below. Learn more at https://github.com/waymondo/hoardable#configuration
15
+ #
16
+ # Hoardable.enabled = true
17
+ # Hoardable.version_updates = true
18
+ # Hoardable.save_trash = true
19
+ TEXT
30
20
  end
31
21
 
32
22
  def create_migration_file
33
- migration_template 'install.rb.erb', 'db/migrate/install_hoardable.rb'
23
+ migration_template "install.rb.erb", "db/migrate/install_hoardable.rb"
34
24
  end
35
25
 
36
26
  def create_functions
37
- Dir.glob(File.join(__dir__, 'functions', '*.sql')).each do |file_path|
38
- file_name = file_path.match(%r{([^/]+)\.sql})[1]
39
- template file_path, "db/functions/#{file_name}_v01.sql"
40
- end
27
+ Dir
28
+ .glob(File.join(__dir__, "functions", "*.sql"))
29
+ .each do |file_path|
30
+ file_name = file_path.match(%r{([^/]+)\.sql})[1]
31
+ template file_path, "db/functions/#{file_name}_v01.sql"
32
+ end
41
33
  end
42
34
 
43
- def self.supports_schema_enums?
44
- ActiveRecord.version >= ::Gem::Version.new('7.0.0')
35
+ no_tasks do
36
+ def postgres_version
37
+ ActiveRecord::Base
38
+ .connection
39
+ .select_value("SELECT VERSION()")
40
+ .match(/[0-9]{1,2}([,.][0-9]{1,2})?/)[
41
+ 0
42
+ ].to_f
43
+ end
45
44
  end
46
45
 
47
46
  def self.next_migration_number(dir)
@@ -1,23 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rails/generators'
4
- require 'rails/generators/active_record/migration/migration_generator'
3
+ require "rails/generators"
4
+ require "rails/generators/active_record/migration/migration_generator"
5
5
 
6
6
  module Hoardable
7
7
  # Generates a migration to create an inherited uni-temporal table of a model including
8
8
  # {Hoardable::Model}, for the storage of +versions+.
9
9
  class MigrationGenerator < ActiveRecord::Generators::Base
10
- source_root File.expand_path('templates', __dir__)
10
+ source_root File.expand_path("templates", __dir__)
11
11
  include Rails::Generators::Migration
12
12
  class_option(
13
13
  :foreign_key_type,
14
14
  type: :string,
15
15
  optional: true,
16
- desc: 'explictly set / override the foreign key type of the versions table'
16
+ desc: "explictly set / override the foreign key type of the versions table"
17
17
  )
18
18
 
19
19
  def create_versions_table
20
- migration_template 'migration.rb.erb', "db/migrate/create_#{singularized_table_name}_versions.rb"
20
+ migration_template(
21
+ "migration.rb.erb",
22
+ "db/migrate/create_#{singularized_table_name}_versions.rb"
23
+ )
21
24
  end
22
25
 
23
26
  def create_triggers
@@ -36,15 +39,15 @@ module Hoardable
36
39
  no_tasks do
37
40
  def foreign_key_type
38
41
  options[:foreign_key_type] ||
39
- class_name.singularize.constantize.columns.find { |col| col.name == 'id' }.sql_type
42
+ class_name.singularize.constantize.columns.find { |col| col.name == primary_key }.sql_type
40
43
  rescue StandardError
41
- 'bigint'
44
+ "bigint"
42
45
  end
43
46
 
44
47
  def primary_key
45
48
  options[:primary_key] || class_name.singularize.constantize.primary_key
46
49
  rescue StandardError
47
- 'id'
50
+ "id"
48
51
  end
49
52
 
50
53
  def singularized_table_name
@@ -2,33 +2,10 @@
2
2
 
3
3
  class InstallHoardable < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
4
4
  def change
5
- create_function :hoardable_prevent_update_id
5
+ <% if postgres_version < 13 %>enable_extension :pgcrypto
6
+ <% end %>create_function :hoardable_prevent_update_id
6
7
  create_function :hoardable_source_set_id
7
8
  create_function :hoardable_version_prevent_update
8
- <% if supports_schema_enums? %>
9
9
  create_enum :hoardable_operation, %w[update delete insert]
10
- <% else %>
11
- reversible do |dir|
12
- dir.up do
13
- execute(
14
- <<~SQL.squish
15
- DO $$
16
- BEGIN
17
- IF NOT EXISTS (
18
- SELECT 1 FROM pg_type t WHERE t.typname = 'hoardable_operation'
19
- ) THEN
20
- CREATE TYPE hoardable_operation AS ENUM ('update', 'delete', 'insert');
21
- END IF;
22
- END
23
- $$;
24
- SQL
25
- )
26
- end
27
-
28
- dir.down do
29
- execute('DROP TYPE IF EXISTS hoardable_operation;')
30
- end
31
- end
32
- <% end %>
33
10
  end
34
11
  end
@@ -4,7 +4,11 @@ class Create<%= class_name.singularize.delete(':') %>Versions < ActiveRecord::Mi
4
4
  def change
5
5
  add_column :<%= table_name %>, :hoardable_id, :<%= foreign_key_type %>
6
6
  add_index :<%= table_name %>, :hoardable_id
7
- create_table :<%= singularized_table_name %>_versions, id: false, options: 'INHERITS (<%= table_name %>)' do |t|
7
+ create_table(
8
+ :<%= singularized_table_name %>_versions,
9
+ id: false,
10
+ options: 'INHERITS (<%= table_name %>)',
11
+ ) do |t|
8
12
  t.jsonb :_data
9
13
  t.tsrange :_during, null: false
10
14
  t.uuid :_event_uuid, null: false, index: true
@@ -12,6 +16,8 @@ class Create<%= class_name.singularize.delete(':') %>Versions < ActiveRecord::Mi
12
16
  end
13
17
  reversible do |dir|
14
18
  dir.up do
19
+ execute('ALTER TABLE <%= singularized_table_name %>_versions ADD PRIMARY KEY (<%= primary_key %>);')
20
+ # remove the following line if you plan on seeding +hoardable_id+ outside the migration
15
21
  execute('UPDATE <%= table_name %> SET hoardable_id = <%= primary_key %>;')
16
22
  end
17
23
  end
@@ -0,0 +1,51 @@
1
+ module Hoardable
2
+ # This is a monkey patch of JOIN related {Arel::Visitors} for PostgreSQL so that they can append
3
+ # the ONLY clause when known to be operating on a {Hoardable::Model}. Ideally, {Arel} itself would
4
+ # provide a mechanism to support this keyword.
5
+ module ArelVisitors
6
+ def visit_Arel_Nodes_FullOuterJoin(o, collector)
7
+ collector << "FULL OUTER JOIN "
8
+ hoardable_maybe_add_only(o, collector)
9
+ collector = visit o.left, collector
10
+ collector << " "
11
+ visit o.right, collector
12
+ end
13
+
14
+ def visit_Arel_Nodes_OuterJoin(o, collector)
15
+ collector << "LEFT OUTER JOIN "
16
+ hoardable_maybe_add_only(o, collector)
17
+ collector = visit o.left, collector
18
+ collector << " "
19
+ visit o.right, collector
20
+ end
21
+
22
+ def visit_Arel_Nodes_RightOuterJoin(o, collector)
23
+ collector << "RIGHT OUTER JOIN "
24
+ hoardable_maybe_add_only(o, collector)
25
+ collector = visit o.left, collector
26
+ collector << " "
27
+ visit o.right, collector
28
+ end
29
+
30
+ def visit_Arel_Nodes_InnerJoin(o, collector)
31
+ collector << "INNER JOIN "
32
+ hoardable_maybe_add_only(o, collector)
33
+ collector = visit o.left, collector
34
+ if o.right
35
+ collector << " "
36
+ visit(o.right, collector)
37
+ else
38
+ collector
39
+ end
40
+ end
41
+
42
+ private def hoardable_maybe_add_only(o, collector)
43
+ return unless o.left.instance_variable_get("@klass").in?(Hoardable::REGISTRY)
44
+ return if Hoardable.instance_variable_get("@at")
45
+
46
+ collector << "ONLY "
47
+ end
48
+ end
49
+ end
50
+
51
+ Arel::Visitors::PostgreSQL.prepend Hoardable::ArelVisitors
@@ -13,9 +13,13 @@ module Hoardable
13
13
  delegate :version_class, to: :source_record
14
14
 
15
15
  def insert_hoardable_version(operation, &block)
16
- version = version_class.insert(initialize_version_attributes(operation), returning: source_primary_key.to_sym)
16
+ version =
17
+ version_class.insert(
18
+ initialize_version_attributes(operation),
19
+ returning: source_primary_key.to_sym
20
+ )
17
21
  version_id = version[0][source_primary_key]
18
- source_record.instance_variable_set('@hoardable_version', version_class.find(version_id))
22
+ source_record.instance_variable_set("@hoardable_version", version_class.find(version_id))
19
23
  source_record.run_callbacks(:versioned, &block)
20
24
  end
21
25
 
@@ -24,40 +28,50 @@ module Hoardable
24
28
  end
25
29
 
26
30
  def find_or_initialize_hoardable_event_uuid
27
- Thread.current[:hoardable_event_uuid] ||= ActiveRecord::Base.connection.query('SELECT gen_random_uuid();')[0][0]
31
+ Thread.current[:hoardable_event_uuid] ||= (
32
+ ActiveRecord::Base.connection.query("SELECT gen_random_uuid();")[0][0]
33
+ )
28
34
  end
29
35
 
30
36
  def initialize_version_attributes(operation)
31
37
  source_attributes_without_primary_key.merge(
32
38
  source_record.changes.transform_values { |h| h[0] },
33
39
  {
34
- 'hoardable_id' => source_record.id,
35
- '_event_uuid' => find_or_initialize_hoardable_event_uuid,
36
- '_operation' => operation,
37
- '_data' => initialize_hoardable_data.merge(changes: source_record.changes),
38
- '_during' => initialize_temporal_range
40
+ "hoardable_id" => source_record.id,
41
+ "_event_uuid" => find_or_initialize_hoardable_event_uuid,
42
+ "_operation" => operation,
43
+ "_data" => initialize_hoardable_data.merge(changes: source_record.changes),
44
+ "_during" => initialize_temporal_range
39
45
  }
40
46
  )
41
47
  end
42
48
 
43
49
  def has_one_find_conditions(reflection)
44
50
  {
45
- reflection.type => source_record.class.name.sub(/Version$/, ''),
51
+ reflection.type => source_record.class.name.sub(/Version$/, ""),
46
52
  reflection.foreign_key => source_record.hoardable_id,
47
- 'name' => (reflection.name.to_s.sub(/^rich_text_/, '') if reflection.class_name.match?(/RichText$/))
53
+ "name" =>
54
+ (reflection.name.to_s.sub(/^rich_text_/, "") if reflection.class_name.match?(/RichText$/))
48
55
  }.reject { |k, v| k.nil? || v.nil? }
49
56
  end
50
57
 
51
58
  def has_one_at_timestamp
52
- Hoardable.instance_variable_get('@at') || source_record.updated_at
59
+ Hoardable.instance_variable_get("@at") || source_record.updated_at
53
60
  rescue NameError
54
61
  raise(UpdatedAtColumnMissingError, source_record.class.table_name)
55
62
  end
56
63
 
57
64
  def source_attributes_without_primary_key
58
- source_record.attributes.without(source_primary_key, *generated_column_names).merge(
59
- source_record.class.select(refreshable_column_names).find(source_record.id).slice(refreshable_column_names)
60
- )
65
+ source_record
66
+ .attributes
67
+ .without(source_primary_key, *generated_column_names)
68
+ .merge(
69
+ source_record
70
+ .class
71
+ .select(refreshable_column_names)
72
+ .find(source_record.id)
73
+ .slice(refreshable_column_names)
74
+ )
61
75
  end
62
76
 
63
77
  def generated_column_names
@@ -67,9 +81,15 @@ module Hoardable
67
81
  end
68
82
 
69
83
  def refreshable_column_names
70
- @refreshable_column_names ||= source_record.class.columns.select(&:default_function).reject do |column|
71
- column.name == source_primary_key || column.name.in?(generated_column_names)
72
- end.map(&:name)
84
+ @refreshable_column_names ||=
85
+ source_record
86
+ .class
87
+ .columns
88
+ .select(&:default_function)
89
+ .reject do |column|
90
+ column.name == source_primary_key || column.name.in?(generated_column_names)
91
+ end
92
+ .map(&:name)
73
93
  end
74
94
 
75
95
  def initialize_temporal_range
@@ -77,9 +97,7 @@ module Hoardable
77
97
  end
78
98
 
79
99
  def initialize_hoardable_data
80
- DATA_KEYS.to_h do |key|
81
- [key, assign_hoardable_context(key)]
82
- end
100
+ DATA_KEYS.to_h { |key| [key, assign_hoardable_context(key)] }
83
101
  end
84
102
 
85
103
  def assign_hoardable_context(key)
@@ -89,18 +107,18 @@ module Hoardable
89
107
  end
90
108
 
91
109
  def unset_hoardable_version_and_event_uuid
92
- source_record.instance_variable_set('@hoardable_version', nil)
110
+ source_record.instance_variable_set("@hoardable_version", nil)
93
111
  return if source_record.class.connection.transaction_open?
94
112
 
95
113
  Thread.current[:hoardable_event_uuid] = nil
96
114
  end
97
115
 
98
116
  def previous_temporal_tsrange_end
99
- source_record.versions.only_most_recent.pluck('_during').first&.end
117
+ source_record.versions.only_most_recent.pluck("_during").first&.end
100
118
  end
101
119
 
102
120
  def hoardable_source_epoch
103
- return source_record.created_at if source_record.class.column_names.include?('created_at')
121
+ return source_record.created_at if source_record.class.column_names.include?("created_at")
104
122
 
105
123
  raise CreatedAtColumnMissingError, source_record.class.table_name
106
124
  end
@@ -2,6 +2,8 @@
2
2
 
3
3
  # An +ActiveRecord+ extension for keeping versions of records in uni-temporal inherited tables.
4
4
  module Hoardable
5
+ REGISTRY = Set.new
6
+
5
7
  # Symbols for use with setting contextual data, when creating versions. See
6
8
  # {file:README.md#tracking-contextual-data README} for more.
7
9
  DATA_KEYS = %i[meta whodunit event_uuid].freeze
@@ -10,60 +12,47 @@ module Hoardable
10
12
  # README} for more.
11
13
  CONFIG_KEYS = %i[enabled version_updates save_trash].freeze
12
14
 
13
- VERSION_CLASS_SUFFIX = 'Version'
15
+ VERSION_CLASS_SUFFIX = "Version"
14
16
  private_constant :VERSION_CLASS_SUFFIX
15
17
 
16
18
  VERSION_TABLE_SUFFIX = "_#{VERSION_CLASS_SUFFIX.tableize}"
17
19
  private_constant :VERSION_TABLE_SUFFIX
18
20
 
19
- DURING_QUERY = '_during @> ?::timestamp'
21
+ DURING_QUERY = "_during @> ?::timestamp"
20
22
  private_constant :DURING_QUERY
21
23
 
22
- HOARDABLE_CALLBACKS_ENABLED = proc do |source_model|
23
- source_model.class.hoardable_config[:enabled] && !source_model.class.name.end_with?(VERSION_CLASS_SUFFIX)
24
- end.freeze
24
+ HOARDABLE_CALLBACKS_ENABLED =
25
+ proc do |source_model|
26
+ source_model.class.hoardable_config[:enabled] &&
27
+ !source_model.class.name.end_with?(VERSION_CLASS_SUFFIX)
28
+ end.freeze
25
29
  private_constant :HOARDABLE_CALLBACKS_ENABLED
26
30
 
27
- HOARDABLE_SAVE_TRASH = proc do |source_model|
28
- source_model.class.hoardable_config[:save_trash]
29
- end.freeze
31
+ HOARDABLE_SAVE_TRASH =
32
+ proc { |source_model| source_model.class.hoardable_config[:save_trash] }.freeze
30
33
  private_constant :HOARDABLE_SAVE_TRASH
31
34
 
32
- HOARDABLE_VERSION_UPDATES = proc do |source_model|
33
- source_model.class.hoardable_config[:version_updates]
34
- end.freeze
35
+ HOARDABLE_VERSION_UPDATES =
36
+ proc { |source_model| source_model.class.hoardable_config[:version_updates] }.freeze
35
37
  private_constant :HOARDABLE_VERSION_UPDATES
36
38
 
37
- SUPPORTS_ENCRYPTED_ACTION_TEXT = ActiveRecord.version >= ::Gem::Version.new('7.0.4')
39
+ SUPPORTS_ENCRYPTED_ACTION_TEXT = ActiveRecord.version >= ::Gem::Version.new("7.0.4")
38
40
  private_constant :SUPPORTS_ENCRYPTED_ACTION_TEXT
39
41
 
40
- SUPPORTS_VIRTUAL_COLUMNS = ActiveRecord.version >= ::Gem::Version.new('7.0.0')
41
- private_constant :SUPPORTS_VIRTUAL_COLUMNS
42
-
43
42
  @context = {}
44
- @config = CONFIG_KEYS.to_h do |key|
45
- [key, true]
46
- end
43
+ @config = CONFIG_KEYS.to_h { |key| [key, true] }
47
44
 
48
45
  class << self
49
46
  CONFIG_KEYS.each do |key|
50
- define_method(key) do
51
- @config[key]
52
- end
47
+ define_method(key) { @config[key] }
53
48
 
54
- define_method("#{key}=") do |value|
55
- @config[key] = value
56
- end
49
+ define_method("#{key}=") { |value| @config[key] = value }
57
50
  end
58
51
 
59
52
  DATA_KEYS.each do |key|
60
- define_method(key) do
61
- @context[key]
62
- end
53
+ define_method(key) { @context[key] }
63
54
 
64
- define_method("#{key}=") do |value|
65
- @context[key] = value
66
- end
55
+ define_method("#{key}=") { |value| @context[key] = value }
67
56
  end
68
57
 
69
58
  # This is a general use method for setting {file:README.md#tracking-contextual-data Contextual
@@ -102,10 +91,20 @@ module Hoardable
102
91
  class Engine < ::Rails::Engine
103
92
  isolate_namespace Hoardable
104
93
 
105
- initializer 'hoardable.action_text' do
94
+ initializer "hoardable.action_text" do
106
95
  ActiveSupport.on_load(:action_text_rich_text) do
107
- require_relative 'rich_text'
108
- require_relative 'encrypted_rich_text' if SUPPORTS_ENCRYPTED_ACTION_TEXT
96
+ require_relative "rich_text"
97
+ require_relative "encrypted_rich_text" if SUPPORTS_ENCRYPTED_ACTION_TEXT
98
+ end
99
+ end
100
+
101
+ initializer "hoardable.schema_statements" do
102
+ ActiveSupport.on_load(:active_record_postgresqladapter) do
103
+ # We need to control the table dumping order of tables, so revert these to just +super+
104
+ Fx::SchemaDumper::Trigger.module_eval("def tables(streams); super; end")
105
+
106
+ ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaDumper.prepend(SchemaDumper)
107
+ ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaStatements.prepend(SchemaStatements)
109
108
  end
110
109
  end
111
110
  end
@@ -2,29 +2,26 @@
2
2
 
3
3
  module Hoardable
4
4
  # A subclass of +StandardError+ for general use within {Hoardable}.
5
- class Error < StandardError; end
5
+ class Error < StandardError
6
+ end
6
7
 
7
8
  # An error to be raised when 'created_at' columns are missing for {Hoardable::Model}s.
8
9
  class CreatedAtColumnMissingError < Error
9
10
  def initialize(source_table_name)
10
- super(
11
- <<~LOG
11
+ super(<<~LOG)
12
12
  '#{source_table_name}' does not have a 'created_at' column, so the start of the first
13
13
  version’s temporal period cannot be known. Add a 'created_at' column to '#{source_table_name}'.
14
14
  LOG
15
- )
16
15
  end
17
16
  end
18
17
 
19
18
  # An error to be raised when 'updated_at' columns are missing for {Hoardable::Model}s.
20
19
  class UpdatedAtColumnMissingError < Error
21
20
  def initialize(source_table_name)
22
- super(
23
- <<~LOG
21
+ super(<<~LOG)
24
22
  '#{source_table_name}' does not have an 'updated_at' column, so Hoardable cannot look up
25
23
  associated record versions with it. Add an 'updated_at' column to '#{source_table_name}'.
26
24
  LOG
27
- )
28
25
  end
29
26
  end
30
27
  end
@@ -17,9 +17,7 @@ module Hoardable
17
17
  private
18
18
 
19
19
  def hoardable_ids(ids)
20
- ids.map do |id|
21
- version_class.where(hoardable_id: id).select(primary_key).ids[0] || id
22
- end
20
+ ids.map { |id| version_class.where(hoardable_id: id).select(primary_key).ids[0] || id }
23
21
  end
24
22
  end
25
23
  end
@@ -12,15 +12,9 @@ module Hoardable
12
12
  @scope ||= hoardable_scope
13
13
  end
14
14
 
15
- private
16
-
17
- def hoardable_scope
18
- if Hoardable.instance_variable_get('@at') && (hoardable_id = @association.owner.hoardable_id)
19
- if @association.reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
20
- @association.reflection.source_reflection.instance_variable_set(
21
- '@active_record_primary_key', 'hoardable_id'
22
- )
23
- end
15
+ private def hoardable_scope
16
+ if Hoardable.instance_variable_get("@at") &&
17
+ (hoardable_id = @association.owner.hoardable_id)
24
18
  @association.scope.rewhere(@association.reflection.foreign_key => hoardable_id)
25
19
  else
26
20
  @association.scope
@@ -32,7 +26,9 @@ module Hoardable
32
26
  class_methods do
33
27
  def has_many(*args, &block)
34
28
  options = args.extract_options!
35
- options[:extend] = Array(options[:extend]).push(HasManyExtension) if options.delete(:hoardable)
29
+ options[:extend] = Array(options[:extend]).push(HasManyExtension) if options.delete(
30
+ :hoardable
31
+ )
36
32
  super(*args, **options, &block)
37
33
 
38
34
  # This hack is needed to force Rails to not use any existing method cache so that the
@@ -6,16 +6,23 @@ module Hoardable
6
6
  extend ActiveSupport::Concern
7
7
 
8
8
  class_methods do
9
- def has_rich_text(name, encrypted: false, hoardable: false)
10
- if SUPPORTS_ENCRYPTED_ACTION_TEXT
11
- super(name, encrypted: encrypted)
12
- else
13
- super(name)
14
- end
9
+ def has_rich_text(name, hoardable: false, **opts)
10
+ super(name, **opts)
15
11
  return unless hoardable
16
12
 
17
13
  reflection_options = reflections["rich_text_#{name}"].options
18
- reflection_options[:class_name] = reflection_options[:class_name].sub(/ActionText/, 'Hoardable')
14
+
15
+ # load the +ActionText+ class if it hasn’t been already
16
+ reflection_options[:class_name].constantize
17
+
18
+ reflection_options[:class_name] = reflection_options[:class_name].sub(
19
+ /^ActionText/,
20
+ "Hoardable"
21
+ )
22
+ end
23
+
24
+ def has_hoardable_rich_text(name, **opts)
25
+ has_rich_text(name, hoardable: true, **opts)
19
26
  end
20
27
  end
21
28
  end
@@ -51,24 +51,27 @@ module Hoardable
51
51
  define_model_callbacks :reverted, only: :after
52
52
  define_model_callbacks :untrashed, only: :after
53
53
 
54
- TracePoint.new(:end) do |trace|
55
- next unless self == trace.self
54
+ TracePoint
55
+ .new(:end) do |trace|
56
+ next unless self == trace.self
56
57
 
57
- full_version_class_name = "#{name}#{VERSION_CLASS_SUFFIX}"
58
- if (namespace_match = full_version_class_name.match(/(.*)::(.*)/))
59
- object_namespace = namespace_match[1].constantize
60
- version_class_name = namespace_match[2]
61
- else
62
- object_namespace = Object
63
- version_class_name = full_version_class_name
64
- end
65
- unless Object.const_defined?(full_version_class_name)
66
- object_namespace.const_set(version_class_name, Class.new(self) { include VersionModel })
67
- end
68
- include SourceModel
58
+ full_version_class_name = "#{name}#{VERSION_CLASS_SUFFIX}"
59
+ if (namespace_match = full_version_class_name.match(/(.*)::(.*)/))
60
+ object_namespace = namespace_match[1].constantize
61
+ version_class_name = namespace_match[2]
62
+ else
63
+ object_namespace = Object
64
+ version_class_name = full_version_class_name
65
+ end
66
+ unless Object.const_defined?(full_version_class_name)
67
+ object_namespace.const_set(version_class_name, Class.new(self) { include VersionModel })
68
+ end
69
+ include SourceModel
70
+ REGISTRY.add(self)
69
71
 
70
- trace.disable
71
- end.enable
72
+ trace.disable
73
+ end
74
+ .enable
72
75
  end
73
76
  end
74
77
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hoardable
4
+ module SchemaDumper
5
+ def ignored?(table_name)
6
+ super || @connection.inherited_table?(table_name)
7
+ end
8
+
9
+ def tables(stream)
10
+ super
11
+ dump_inherited_tables(stream)
12
+ empty_line(stream)
13
+ triggers(stream)
14
+ end
15
+
16
+ private def dump_inherited_tables(stream)
17
+ sorted_tables = @connection.tables.filter { |table| @connection.inherited_table?(table) }.sort
18
+ sorted_tables.each do |table_name|
19
+ table(table_name, stream)
20
+ foreign_keys(table_name, stream)
21
+ end
22
+ end
23
+ end
24
+ private_constant :SchemaDumper
25
+ end