Class: GeneratedImage

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

Overview

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.

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.

== 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 =

Statuses.

%w[pending imported rejected].freeze
STALE_AFTER =

Stale after.

48.hours

Constants included from Models::Schedulable

Models::Schedulable::SIMPLE_FORM_OPTIONS

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::Schedulable

config

Methods included from Models::AfterCommittable

#after_commit

Methods included from Models::EventPublishable

#publish_event

Instance Attribute Details

#aspect_ratioObject (readonly)

Validates presence of the requested aspect ratio.

Validations:



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

validates :aspect_ratio, presence: true

#image_sizeObject (readonly)

Validates presence of the requested image size.

Validations:



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

validates :image_size,   presence: true

#modelObject (readonly)

Validates presence of the model name used for generation.

Validations:



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

validates :model,        presence: true

#promptObject (readonly)

Validates presence of the generation prompt.

Validations:



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

validates :prompt,       presence: true

#statusObject (readonly)

Validates the lifecycle status is one of STATUSES.

Validations:



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

validates :status,       inclusion: { in: STATUSES }

Class Method Details

.importedActiveRecord::Relation<GeneratedImage>

A relation of GeneratedImages that are imported. Active Record Scope

Returns:

See Also:



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

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

.pendingActiveRecord::Relation<GeneratedImage>

A relation of GeneratedImages that are pending. Active Record Scope

Returns:

See Also:



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

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

.staleActiveRecord::Relation<GeneratedImage>

A relation of GeneratedImages that are stale. Active Record Scope

Returns:

See Also:



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

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

Instance Method Details

#created_byAccount

Account that requested the generation.

Returns:

See Also:



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

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

#delete_ik_asset!void

This method returns an undefined value.

Deletes the asset from ImageKit; logs a warning on failure.



112
113
114
115
116
117
118
119
# File 'app/models/generated_image.rb', line 112

def delete_ik_asset!
  fid = ik_file_id
  return if fid.blank?

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

#ik_file_idString?


ImageKit asset helpers (mirrors Image#ik_* methods)

ImageKit file id of the stored asset.

Returns:

  • (String, nil)


94
95
96
# File 'app/models/generated_image.rb', line 94

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

#ik_pathString?

ImageKit file path of the stored asset.

Returns:

  • (String, nil)


100
101
102
# File 'app/models/generated_image.rb', line 100

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

#ik_urlString?

ImageKit URL of the stored asset.

Returns:

  • (String, nil)


106
107
108
# File 'app/models/generated_image.rb', line 106

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

#reference_imagesObject

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



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

def reference_images
  return Image.none if reference_image_ids.blank?

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

#source_imageImage

Source library image the generation was based on.

Returns:

See Also:



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

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

#source_recordSourceRecord

Record (polymorphic) this generated image is attached to.

Returns:

  • (SourceRecord)

See Also:



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

belongs_to :source_record, polymorphic: true, optional: true