Class: GeneratedImage

Inherits:
ApplicationRecord show all
Defined in:
app/models/generated_image.rb

Overview

An AI-generated image staging record: created by +ImageGenerationWorker+ after
a successful generation and upload to ImageKit, pending user review.

The user is shown a preview (generated_images#show) where they can:

  • Fill in title, tags, and category, then import to the library (update)
  • Request revisions with written feedback (refine)
  • Discard (destroy)

Stale pending records (> 48 h) are cleaned up by +GeneratedImageCleanupWorker+.

The +ik_asset+ JSONB column mirrors the shape of +Image#asset+ so the
import action can construct a real Image record without a second upload.

NOTE: Not named +ImageGeneration+ because that namespace is already occupied by
the +ImageGeneration::Service+ / +ImageGeneration::GeminiService+ service
classes. Zeitwerk would create a conflicting implicit module constant.

== Schema Information

Table name: generated_images
Database name: primary

id :bigint not null, primary key
aspect_ratio :string default("1:1"), not null
ik_asset :jsonb not null
image_size :string default("1K"), not null
model :string not null
prompt :text not null
reference_image_ids :integer default([]), not null, is an Array
source_record_type :string
status :string default("pending"), not null
suggested_title :string
created_at :datetime not null
updated_at :datetime not null
created_by_id :bigint
source_image_id :bigint
source_record_id :bigint

Indexes

idx_generated_images_on_source_record (source_record_type,source_record_id)
index_generated_images_on_created_at (created_at)
index_generated_images_on_created_by_id (created_by_id)
index_generated_images_on_source_image_id (source_image_id)
index_generated_images_on_status (status)

Foreign Keys

fk_rails_... (created_by_id => accounts.id)
fk_rails_... (source_image_id => digital_assets.id) ON DELETE => cascade

Constant Summary collapse

STATUSES =
%w[pending imported rejected].freeze
STALE_AFTER =
48.hours

Instance Attribute Summary collapse

Belongs to collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from ApplicationRecord

ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation

Methods included from Models::EventPublishable

#publish_event

Instance Attribute Details

#aspect_ratioObject (readonly)



64
# File 'app/models/generated_image.rb', line 64

validates :aspect_ratio, presence: true

#image_sizeObject (readonly)



65
# File 'app/models/generated_image.rb', line 65

validates :image_size,   presence: true

#modelObject (readonly)



63
# File 'app/models/generated_image.rb', line 63

validates :model,        presence: true

#promptObject (readonly)



62
# File 'app/models/generated_image.rb', line 62

validates :prompt,       presence: true

#statusObject (readonly)



66
# File 'app/models/generated_image.rb', line 66

validates :status,       inclusion: { in: STATUSES }

Class Method Details

.importedActiveRecord::Relation<GeneratedImage>

A relation of GeneratedImages that are imported. Active Record Scope

Returns:

See Also:



69
# File 'app/models/generated_image.rb', line 69

scope :imported, -> { where(status: 'imported') }

.pendingActiveRecord::Relation<GeneratedImage>

A relation of GeneratedImages that are pending. Active Record Scope

Returns:

See Also:



68
# File 'app/models/generated_image.rb', line 68

scope :pending,  -> { where(status: 'pending') }

.staleActiveRecord::Relation<GeneratedImage>

A relation of GeneratedImages that are stale. Active Record Scope

Returns:

See Also:



70
# File 'app/models/generated_image.rb', line 70

scope :stale,    -> { pending.where(created_at: ...STALE_AFTER.ago) }

Instance Method Details

#created_byAccount

Returns:

See Also:



57
# File 'app/models/generated_image.rb', line 57

belongs_to :created_by,    class_name: 'Account', optional: true

#delete_ik_asset!Object



95
96
97
98
99
100
101
102
# File 'app/models/generated_image.rb', line 95

def delete_ik_asset!
  fid = ik_file_id
  return unless fid.present?

  ImageKitFactory.delete_file(fid)
rescue StandardError => e
  Rails.logger.warn "[GeneratedImage##{id}] delete_ik_asset! failed: #{e.message}"
end

#ik_file_idObject


ImageKit asset helpers (mirrors Image#ik_* methods)



83
84
85
# File 'app/models/generated_image.rb', line 83

def ik_file_id
  ik_asset&.dig('file_id') || ik_asset&.dig('fileId')
end

#ik_pathObject



87
88
89
# File 'app/models/generated_image.rb', line 87

def ik_path
  ik_asset&.dig('file_path') || ik_asset&.dig('filePath')
end

#ik_urlObject



91
92
93
# File 'app/models/generated_image.rb', line 91

def ik_url
  ik_asset&.dig('url')
end

#reference_imagesObject

Library images used as generation references (array column → AR association-like).



73
74
75
76
77
# File 'app/models/generated_image.rb', line 73

def reference_images
  return Image.none if reference_image_ids.blank?

  Image.where(id: reference_image_ids).order(:id)
end

#source_imageImage

Returns:

See Also:



55
# File 'app/models/generated_image.rb', line 55

belongs_to :source_image,  class_name: 'Image', optional: true

#source_recordSourceRecord

Returns:

  • (SourceRecord)

See Also:



56
# File 'app/models/generated_image.rb', line 56

belongs_to :source_record, polymorphic: true,    optional: true