Class: Api::V1::OembedController
- Inherits:
-
BaseController
- Object
- ActionController::API
- BaseController
- Api::V1::OembedController
- Defined in:
- app/controllers/api/v1/oembed_controller.rb
Overview
oEmbed API endpoint for Redactor 4 embed plugin
Converts URLs (YouTube, Vimeo, WarmlyYours videos, etc.) to embeddable HTML
For external providers: Uses ruby-oembed gem with built-in providers + Noembed fallback
For WY videos: Uses custom Oembed::WyVideoProvider for proper Shaka player support
Providers are registered in config/initializers/oembed.rb
Examples:
GET /api/v1/oembed?url=https://www.youtube.com/watch?v=dQw4w9WgXcQ
=> { html: "<iframe ...>", type: "video", provider_name: "YouTube" }
GET /api/v1/oembed?url=https://www.warmlyyours.com/videos/my-video-slug
=> { html: "...", type: "video", provider_name: "WarmlyYours" }
Instance Method Summary collapse
-
#faq ⇒ Object
GET /api/v1/oembed/faq Returns rendered FAQ HTML for embedding in Redactor editor.
-
#image ⇒ Object
GET /api/v1/oembed/image Returns rendered image HTML for embedding in Redactor editor Uses image_asset_tag for consistent rendering with the rest of the site.
-
#product ⇒ Object
GET /api/v1/oembed/product Returns rendered product HTML for embedding in Redactor editor Shows a magazine-style product card with image, title, SKU, price, and add-to-cart.
-
#show ⇒ Object
GET /api/v1/oembed Required params: url - The URL to convert to embed HTML Optional params: maxwidth - Maximum width for the embed (default: 800) maxheight - Maximum height for the embed (default: 600).
-
#video ⇒ Object
GET /api/v1/oembed/video Returns rendered video HTML for embedding in Redactor editor Uses Shaka player with HLS/captions support.
Methods inherited from BaseController
#catalog_for_request, #error!, #locale_for_request, #logger, #render_bad_request_response, #render_internal_server_error, #render_not_found_response, #render_result, #render_unprocessable_entity_response, #set_locale, #store_for_request, #underscore_params
Instance Method Details
#faq ⇒ Object
GET /api/v1/oembed/faq
Returns rendered FAQ HTML for embedding in Redactor editor
Required params (one of):
uuid - EmbeddedAsset UUID (new flow, preferred)
ids - Comma-separated FAQ IDs (legacy flow)
Optional params:
title - Custom section title
sort - Sort option: 'popularity' for most helpful first
Example:
GET /api/v1/oembed/faq?uuid=abc123-...
GET /api/v1/oembed/faq?ids=123,456&title=Custom%20Title&sort=popularity
=> { html: "...", type: "rich", faq_ids: [123, 456] }
63 64 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 90 91 92 93 94 |
# File 'app/controllers/api/v1/oembed_controller.rb', line 63 def faq Rails.logger.debug { "[oEmbed] FAQ params received: #{params.to_unsafe_h.inspect}" } # Support UUID-based lookup (new flow) or direct ids (legacy flow) return render_faq_by_uuid(params[:uuid]) if params[:uuid].present? ids = params[:ids].to_s.split(',').map(&:strip).map(&:to_i).reject(&:zero?) return render json: { error: 'ids or uuid parameter is required' }, status: :bad_request if ids.empty? provider = Oembed::FaqProvider.new result = provider.get( ids: ids, title: params[:title], sort: params[:sort] ) render json: { html: result[:html], type: result[:type], provider_name: result[:provider_name], title: result[:title], faq_ids: result[:faq_ids], faq_count: result[:faq_count] } rescue Oembed::FaqProvider::FaqNotFoundError => e Rails.logger.warn("[oEmbed] FAQ not found: #{ids.join(',')} - #{e.}") render json: { error: e. }, status: :not_found rescue StandardError => e Rails.logger.error("[oEmbed] Error fetching FAQ embed: #{ids.join(',')} - #{e.class}: #{e.}") render json: { error: 'Failed to fetch FAQ embed data' }, status: :internal_server_error end |
#image ⇒ Object
GET /api/v1/oembed/image
Returns rendered image HTML for embedding in Redactor editor
Uses image_asset_tag for consistent rendering with the rest of the site
Required params:
image_id - The image ID from the library
Optional params (ImageKit transformations):
width, height - Target dimensions
crop_x, crop_y, crop_w, crop_h - Crop area
crop_mode - Crop mode (pad_resize, force, etc.)
rotate - Rotation in degrees
blur - Blur amount (1-100)
background - Background color for padding
encode_format - Output format (jpeg, png, webp)
Optional params (display):
caption - Image caption text
alt - Alt text override
link - URL to wrap image in link
link_target - Link target (_blank, etc.)
lazyload - Enable lazy loading (default: true)
include_srcset - Include responsive srcset (default: true)
wrapper_tag - Wrapper element: 'figure' (default), 'p', or 'div' (for email compatibility)
Example:
GET /api/v1/oembed/image?image_id=123&width=800&caption=My%20caption
=> { html: "...", type: "photo", ... }
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'app/controllers/api/v1/oembed_controller.rb', line 124 def image Rails.logger.debug { "[oEmbed] Image params received: #{params.to_unsafe_h.inspect}" } # Support UUID-based lookup (new flow) or direct image_id (legacy flow) return render_image_by_uuid(params[:uuid]) if params[:uuid].present? image_id = params[:image_id] return render json: { error: 'image_id or uuid parameter is required' }, status: :bad_request if image_id.blank? # Build options from permitted params = image_params.merge(image_id: image_id) Rails.logger.debug { "[oEmbed] Image options after merge: #{.inspect}" } provider = Oembed::ImageProvider.new result = provider.get() render json: { html: result[:html], type: result[:type], provider_name: result[:provider_name], title: result[:title], thumbnail_url: result[:thumbnail_url], width: result[:width], height: result[:height], # Custom fields for editing image_id: result[:image_id], image_slug: result[:image_slug], alt: result[:alt], caption: result[:caption], options: result[:options] } rescue Oembed::ImageProvider::ImageNotFoundError => e Rails.logger.warn("[oEmbed] Image not found: #{image_id} - #{e.}") render json: { error: e. }, status: :not_found rescue StandardError => e Rails.logger.error("[oEmbed] Error fetching image embed: #{image_id} - #{e.class}: #{e.}") Rails.logger.error("[oEmbed] Backtrace: #{e.backtrace.first(10).join("\n")}") render json: { error: "Failed to fetch image embed data: #{e.}" }, status: :internal_server_error end |
#product ⇒ Object
GET /api/v1/oembed/product
Returns rendered product HTML for embedding in Redactor editor
Shows a magazine-style product card with image, title, SKU, price, and add-to-cart
Required params (one of):
uuid - EmbeddedAsset UUID (new flow, preferred)
sku - The product SKU (legacy flow)
Optional params:
locale - Locale for pricing ('en-US' or 'en-CA', defaults to 'en-US')
Example:
GET /api/v1/oembed/product?uuid=abc123-...
GET /api/v1/oembed/product?sku=TRT512-KIT&locale=en-US
=> { html: "...", type: "rich", sku: "TRT512-KIT" }
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
# File 'app/controllers/api/v1/oembed_controller.rb', line 234 def product Rails.logger.debug { "[oEmbed] Product params received: #{params.to_unsafe_h.inspect}" } # Support UUID-based lookup (new flow) or direct sku (legacy flow) return render_product_by_uuid(params[:uuid]) if params[:uuid].present? sku = params[:sku].to_s.strip.upcase locale = params[:locale].presence || I18n.locale.to_s return render json: { error: 'sku or uuid parameter is required' }, status: :bad_request if sku.blank? provider = Oembed::ProductProvider.new result = provider.get(sku: sku, locale: locale) render json: { html: result[:html], type: result[:type], provider_name: result[:provider_name], title: result[:title], sku: result[:sku], image_url: result[:image_url] } rescue Oembed::ProductProvider::ProductNotFoundError => e Rails.logger.warn("[oEmbed] Product not found: #{sku} - #{e.}") render json: { error: e. }, status: :not_found rescue Oembed::ProductProvider::ProductUnavailableError => e Rails.logger.warn("[oEmbed] Product unavailable: #{sku} - #{e.}") render json: { error: e. }, status: :gone rescue StandardError => e Rails.logger.error("[oEmbed] Error fetching product embed: #{sku} - #{e.class}: #{e.}") Rails.logger.error("[oEmbed] Backtrace: #{e.backtrace.first(10).join("\n")}") render json: { error: 'Failed to fetch product embed data' }, status: :internal_server_error end |
#show ⇒ Object
GET /api/v1/oembed
Required params:
url - The URL to convert to embed HTML
Optional params:
maxwidth - Maximum width for the embed (default: 800)
maxheight - Maximum height for the embed (default: 600)
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'app/controllers/api/v1/oembed_controller.rb', line 26 def show url = params[:url] return render json: { error: 'URL parameter is required' }, status: :bad_request if url.blank? # Request oEmbed data with optional size constraints = {} [:maxwidth] = params[:maxwidth].to_i if params[:maxwidth].present? [:maxheight] = params[:maxheight].to_i if params[:maxheight].present? # Set reasonable defaults for embed size [:maxwidth] ||= 800 [:maxheight] ||= 450 # 16:9 aspect ratio # Check if this is a WarmlyYours video URL first wy_provider = Oembed::WyVideoProvider.new return handle_wy_video(url, ) if wy_provider.handles?(url) # Fall through to standard oEmbed providers for external URLs (url, ) end |
#video ⇒ Object
GET /api/v1/oembed/video
Returns rendered video HTML for embedding in Redactor editor
Uses Shaka player with HLS/captions support
Required params (one of):
uuid - EmbeddedAsset UUID (new flow, preferred)
video_id - Video ID (legacy flow)
Optional params:
player_type - 'html5' (default) or 'iframe'
Example:
GET /api/v1/oembed/video?uuid=abc123-...
=> { html: "<video ...data-embedded-asset-uuid='...'...", type: "video", ... }
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'app/controllers/api/v1/oembed_controller.rb', line 179 def video Rails.logger.debug { "[oEmbed] Video params received: #{params.to_unsafe_h.inspect}" } # Support UUID-based lookup (new flow) or direct video_id (legacy flow) return render_video_by_uuid(params[:uuid]) if params[:uuid].present? video_id = params[:video_id] return render json: { error: 'video_id or uuid parameter is required' }, status: :bad_request if video_id.blank? video_record = Video.find_by(id: video_id) return render json: { error: 'Video not found' }, status: :not_found unless video_record # Build video URL and use existing handler # include_wrapper: true so the HTML has the ratio-16x9 wrapper + play button overlay video_url = "https://www.warmlyyours.com/videos/#{video_record.slug}" = { player_type: params[:player_type] || 'html5', include_wrapper: true } provider = Oembed::WyVideoProvider.new result = provider.get(video_url, ) render json: { html: result[:html], type: result[:type], provider_name: result[:provider_name], title: result[:title], thumbnail_url: result[:thumbnail_url], width: result[:width], height: result[:height], video_id: result[:video_id], video_slug: result[:video_slug] } rescue Oembed::WyVideoProvider::VideoNotFoundError => e Rails.logger.warn("[oEmbed] Video not found: #{video_id} - #{e.}") render json: { error: e. }, status: :not_found rescue StandardError => e Rails.logger.error("[oEmbed] Error fetching video embed: #{video_id} - #{e.class}: #{e.}") Rails.logger.error("[oEmbed] Backtrace: #{e.backtrace.first(10).join("\n")}") render json: { error: "Failed to fetch video embed data: #{e.}" }, status: :internal_server_error end |