Class: GeneratedPdf
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- GeneratedPdf
- Defined in:
- app/models/generated_pdf.rb
Overview
An AI-generated / reconstructed PDF staging record — the PDF analogue of
GeneratedImage. Created by +PdfGenerationWorker+ (or the Sunny pdf_generate
tool) after a successful render, pending user review in the PDF studio.
The user reviews the staged PDF (generated_pdfs#show) where they can:
- Edit the +layout+ and regenerate (iterate)
- Import it into the publication library — promotes to a Literature upload +
publication Item via GeneratedPdfImporter (which also persists +layout+
onto the Literature's +source_layout+ so it can be re-opened later) - Discard it
Stale pending records (> 48 h) are reaped by +GeneratedPdfCleanupWorker+.
The staged PDF bytes live in the Dragonfly +:secure+ store (same store as
Upload), so promotion re-materializes them into a real Literature upload.
The +layout+ JSONB is the declarative source-of-truth for iteration.
== Schema Information
Table name: generated_pdfs
Database name: primary
id :bigint not null, primary key
byte_size :integer
content_type :string default("application/pdf"), not null
error :text
file_name :string
file_uid :string
instructions :text
kind :string default("generated"), not null
layout :jsonb not null
page_count :integer
source_record_type :string
status :string default("pending"), not null
suggested_title :string
title :string
created_at :datetime not null
updated_at :datetime not null
created_by_id :bigint
source_publication_id :bigint
source_record_id :bigint
Constant Summary collapse
- STATUSES =
Statuses.
%w[pending imported rejected].freeze
- KINDS =
Kinds — how the PDF was produced.
%w[generated edited reconstructed].freeze
- STALE_AFTER =
Stale after.
48.hours
Constants included from Schedulable
Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
- #kind ⇒ Object readonly
- #status ⇒ Object readonly
Belongs to collapse
Class Method Summary collapse
-
.imported ⇒ ActiveRecord::Relation<GeneratedPdf>
A relation of GeneratedPdfs that are imported.
-
.pending ⇒ ActiveRecord::Relation<GeneratedPdf>
A relation of GeneratedPdfs that are pending.
-
.rejected ⇒ ActiveRecord::Relation<GeneratedPdf>
A relation of GeneratedPdfs that are rejected.
-
.stale ⇒ ActiveRecord::Relation<GeneratedPdf>
A relation of GeneratedPdfs that are stale.
Instance Method Summary collapse
-
#assign_pdf(bytes, filename:) ⇒ Object
Set the staged PDF content and derive byte size in one call.
- #file_stored? ⇒ Boolean
-
#file_url ⇒ Object
App-served URL for embedding the staged PDF in the review viewer.
- #imported? ⇒ Boolean
-
#pdf_bytes ⇒ Object
The staged PDF as raw bytes (nil if nothing stored).
- #pending? ⇒ Boolean
- #rejected? ⇒ Boolean
-
#to_temp_path ⇒ String?
Materialize the staged PDF to a local temp path (for re-processing / import).
Methods inherited from ApplicationRecord
ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation
Methods included from Schedulable
Methods included from Models::AfterCommittable
Methods included from Models::EventPublishable
Instance Attribute Details
#kind ⇒ Object (readonly)
60 |
# File 'app/models/generated_pdf.rb', line 60 validates :kind, inclusion: { in: KINDS } |
#status ⇒ Object (readonly)
59 |
# File 'app/models/generated_pdf.rb', line 59 validates :status, inclusion: { in: STATUSES } |
Class Method Details
.imported ⇒ ActiveRecord::Relation<GeneratedPdf>
A relation of GeneratedPdfs that are imported. Active Record Scope
63 |
# File 'app/models/generated_pdf.rb', line 63 scope :imported, -> { where(status: 'imported') } |
.pending ⇒ ActiveRecord::Relation<GeneratedPdf>
A relation of GeneratedPdfs that are pending. Active Record Scope
62 |
# File 'app/models/generated_pdf.rb', line 62 scope :pending, -> { where(status: 'pending') } |
.rejected ⇒ ActiveRecord::Relation<GeneratedPdf>
A relation of GeneratedPdfs that are rejected. Active Record Scope
64 |
# File 'app/models/generated_pdf.rb', line 64 scope :rejected, -> { where(status: 'rejected') } |
.stale ⇒ ActiveRecord::Relation<GeneratedPdf>
A relation of GeneratedPdfs that are stale. Active Record Scope
65 |
# File 'app/models/generated_pdf.rb', line 65 scope :stale, -> { pending.where(created_at: ...STALE_AFTER.ago) } |
Instance Method Details
#assign_pdf(bytes, filename:) ⇒ Object
Set the staged PDF content and derive byte size in one call. Mirrors
+Upload.uploadify_from_data+: the custom dragonfly_accessor's after_assign
hook needs a named file (a raw string has no name), so write a temp file and
assign it. The temp file is read by Dragonfly at save time.
104 105 106 107 108 109 110 111 112 113 114 |
# File 'app/models/generated_pdf.rb', line 104 def assign_pdf(bytes, filename:) name = filename.to_s name = "#{name}.pdf" unless name.downcase.end_with?('.pdf') path = Upload.temp_location("genpdf_#{SecureRandom.hex(8)}_#{File.basename(name)}") File.binwrite(path, bytes) self.file = File.new(path) self.file_name = name # normalize (after_assign sets the temp basename) self.content_type = 'application/pdf' self.byte_size = bytes.bytesize end |
#created_by ⇒ Account
50 |
# File 'app/models/generated_pdf.rb', line 50 belongs_to :created_by, class_name: 'Account', optional: true |
#file_stored? ⇒ Boolean
94 95 96 |
# File 'app/models/generated_pdf.rb', line 94 def file_stored? file_uid.present? && file.present? end |
#file_url ⇒ Object
App-served URL for embedding the staged PDF in the review viewer.
88 89 90 91 92 |
# File 'app/models/generated_pdf.rb', line 88 def file_url file&.url rescue StandardError nil end |
#imported? ⇒ Boolean
68 |
# File 'app/models/generated_pdf.rb', line 68 def imported? = status == 'imported' |
#pdf_bytes ⇒ Object
The staged PDF as raw bytes (nil if nothing stored).
72 73 74 |
# File 'app/models/generated_pdf.rb', line 72 def pdf_bytes file&.data end |
#pending? ⇒ Boolean
67 |
# File 'app/models/generated_pdf.rb', line 67 def pending? = status == 'pending' |
#rejected? ⇒ Boolean
69 |
# File 'app/models/generated_pdf.rb', line 69 def rejected? = status == 'rejected' |
#source_publication ⇒ Item
48 |
# File 'app/models/generated_pdf.rb', line 48 belongs_to :source_publication, class_name: 'Item', optional: true |
#source_record ⇒ SourceRecord
49 |
# File 'app/models/generated_pdf.rb', line 49 belongs_to :source_record, polymorphic: true, optional: true |
#to_temp_path ⇒ String?
Materialize the staged PDF to a local temp path (for re-processing / import).
Caller is responsible for deleting the returned path.
79 80 81 82 83 84 85 |
# File 'app/models/generated_pdf.rb', line 79 def to_temp_path return nil unless file_stored? path = Rails.application.config.x.temp_storage_path.join("generated_pdf_#{id || SecureRandom.hex(4)}.pdf") File.binwrite(path, file.data) path.to_s end |