Class: ArticleTechnical::Consolidator

Inherits:
Object
  • Object
show all
Defined in:
app/services/article_technical/consolidator.rb

Overview

Creates one reviewable Technical Article draft from multiple approved source
articles. It copies their existing catalog context and evidence links, then
records the sources through ordinary ContentLinks. Source articles remain live
until the draft passes the existing Technical Article approval state machine.

Defined Under Namespace

Classes: Result

Constant Summary collapse

MAX_SOURCE_ARTICLES =

Safety cap for one reviewable consolidation and its approval transaction.

20

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source_article_ids:, author:, attributes:) ⇒ Consolidator

Creates a consolidator.

Parameters:

  • source_article_ids (Array<Integer>)

    approved source article IDs

  • author (Employee)

    draft author and review owner

  • attributes (Hash)

    draft content attributes



56
57
58
59
60
# File 'app/services/article_technical/consolidator.rb', line 56

def initialize(source_article_ids:, author:, attributes:)
  @source_article_ids = Array(source_article_ids).map(&:to_i).select(&:positive?).uniq
  @author = author
  @attributes = attributes.symbolize_keys.slice(:subject, :description, :solution)
end

Class Method Details

.call(source_article_ids:, author:, **attributes) ⇒ Result

Builds and runs a consolidation.

Parameters:

  • source_article_ids (Array<Integer>)

    approved source article IDs

  • author (Employee)

    draft author and review owner

  • attributes (Hash)

    draft subject, description, and solution

Options Hash (**attributes):

  • subject (String)

    draft subject

  • description (String)

    draft description

  • solution (String)

    draft solution

Returns:

  • (Result)

    consolidation outcome



47
48
49
# File 'app/services/article_technical/consolidator.rb', line 47

def self.call(source_article_ids:, author:, **attributes)
  new(source_article_ids:, author:, attributes:).call
end

Instance Method Details

#callResult

Creates the draft without changing any approved source.

Returns:

  • (Result)

    consolidation outcome



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'app/services/article_technical/consolidator.rb', line 65

def call
  article = nil
  ActiveRecord::Base.transaction do
    # All writers of replacement drafts lock their approved sources. Taking
    # the same locks in ID order prevents two concurrent consolidations from
    # creating parallel successors for an overlapping source set.
    sources = load_sources
    validation_errors = validate_sources(sources)
    raise ToolError, validation_errors if validation_errors.any?

    article = build_article(sources)
    article.save!
    copy_related_materials!(article, sources)
    mark_sources!(article, sources)
  end

  Result.new(success: true, article: article)
rescue ToolError => e
  failure(e.messages)
rescue ActiveRecord::RecordInvalid => e
  failure(e.record.errors.full_messages)
rescue StandardError => e
  Rails.logger.error("[ArticleTechnical::Consolidator] Failed: #{e.class}: #{e.message}")
  failure(['Technical Article consolidation failed.'])
end