Class: Posts::EmbeddedAssetSyncService

Inherits:
Object
  • Object
show all
Defined in:
app/services/posts/embedded_asset_sync_service.rb

Overview

Scans a blog post's solution HTML and creates EmbeddedAsset records for any
embedded content widgets (images, videos, FAQs, products) that are missing a
data-embedded-asset-uuid attribute.

This closes the gap where the AI assistant (or old editor paths) inserts
embeds without going through the Redactor widget flow that normally calls
POST /api/v1/embedded_assets to register the asset.

Orphan pruning (removing EmbeddedAsset records whose UUID is no longer in the
HTML) is handled separately by EmbeddedAssets::SyncService, which fires via
the Article after_commit :sync_embedded_assets callback on every save.

Handled patterns:
Images — figure[data-wy-oembed="image"] / .wy-image-embed → EmbeddedImageAsset
— inline img[data-image-id] not in a tracked figure → wrap + EmbeddedImageAsset
Videos — video[data-wy-video-id] / div.wy-video-embed-wrapper → EmbeddedVideoAsset
FAQs — figure[data-wy-oembed="faq"] → EmbeddedFaqAsset (one per FAQ)
Products — figure[data-wy-oembed="product"] → EmbeddedProductAsset

Safe to run repeatedly — embeds that already have a UUID are skipped.
Saves via update_columns (bypasses callbacks) to avoid re-triggering
Events::PostContentUpdated and looping.

Usage:
Posts::EmbeddedAssetSyncService.new(post).call

=> true if HTML or DB records were modified, false otherwise

Instance Method Summary collapse

Constructor Details

#initialize(post) ⇒ EmbeddedAssetSyncService

Returns a new instance of EmbeddedAssetSyncService.



32
33
34
# File 'app/services/posts/embedded_asset_sync_service.rb', line 32

def initialize(post)
  @post = post
end

Instance Method Details

#callObject



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'app/services/posts/embedded_asset_sync_service.rb', line 36

def call
  return false unless @post.solution.present?

  doc = Nokogiri::HTML5.fragment(@post.solution)

  modified = false
  modified |= backfill_image_embeds(doc)
  modified |= backfill_video_embeds(doc)
  modified |= backfill_faq_embeds(doc)
  modified |= backfill_product_embeds(doc)

  if modified
    new_html = doc.to_html
    @post.update_columns(solution: new_html, updated_at: Time.current)
  end

  modified
end