Class: DigitalAsset
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- DigitalAsset
- Extended by:
- FriendlyId
- Includes:
- Models::Auditable, Models::ItemScopable, Models::Taggable, PgSearch::Model
- Defined in:
- app/models/digital_asset.rb
Overview
== Schema Information
Table name: digital_assets
Database name: primary
id :integer not null, primary key
ai_metadata_suggestions :jsonb
ai_visual_description :text
air_date :date
asset :jsonb
attachment_format :string(10)
attachment_height :integer
attachment_mime_type :string
attachment_name :string
attachment_size :integer
attachment_uid :string
attachment_width :integer
background_color :string
category :string(255)
cloudflare_data :jsonb not null
cloudflare_uid :string
duration_in_seconds :integer
expanded_description :text
fingerprint :bigint
fingerprint_legacy :string
image_colorspace :string
image_dpi :integer
inactive :boolean default(FALSE), not null
linked_assets_uids :string default([]), is an Array
locales :string default([]), not null, is an Array
location :string
merged_from_ids :integer default([]), is an Array
meta_description :text
meta_keywords :string
meta_title :string(255)
notes :text
position :integer default(100), not null
poster_format :string
poster_mime_type :string
poster_name :string
poster_offset :integer
poster_uid :string
reference_number :string
series :string
slug :string(140)
source :string
structured_transcript_json :jsonb
sub_header :string(255)
thumbnail_url :string
title :string(255)
transcribed_at :datetime
transcript :text
transcription_state :integer default(0)
translations :jsonb
type :string
url :string(255)
video_has_no_spoken_words :boolean default(FALSE)
vision_analyzed_at :datetime
vision_model_used :string
youtube_caption_synced_at :datetime
youtube_chapters_draft :jsonb
youtube_chapters_generation_error :text
youtube_chapters_generation_status :string
youtube_description :string
youtube_privacy_status :string
youtube_synced_at :datetime
youtube_title :string
youtube_upload_date :datetime
youtube_upload_status :string
created_at :datetime not null
updated_at :datetime not null
assemblyai_transcript_id :string
asset_file_id :string
cloudinary_asset_id :string
creator_id :integer
legacy_wistia_id :string(255)
poster_image_id :integer
purge_cache_request_id :string
updater_id :integer
youtube_id :string
youtube_thumbnail_image_id :integer
Indexes
by_type_inactive_id (type,inactive,id)
index_digital_assets_on_asset_file_id (asset_file_id) UNIQUE
index_digital_assets_on_cloudflare_uid (cloudflare_uid)
index_digital_assets_on_creator_id (creator_id)
index_digital_assets_on_inactive (inactive)
index_digital_assets_on_merged_from_ids (merged_from_ids) USING gin
index_digital_assets_on_poster_image_id (poster_image_id)
index_digital_assets_on_poster_offset (poster_offset)
index_digital_assets_on_slug (slug)
index_digital_assets_on_source (source)
index_digital_assets_on_transcription_state (transcription_state)
index_digital_assets_on_translations (translations) USING gin
index_digital_assets_on_type_and_slug (type,slug) UNIQUE
index_digital_assets_on_updater_id (updater_id)
index_digital_assets_on_url (url)
index_digital_assets_on_vision_analyzed_at (vision_analyzed_at)
index_digital_assets_on_youtube_thumbnail_image_id (youtube_thumbnail_image_id)
index_images_on_fingerprint (fingerprint) WHERE (((type)::text = 'Image'::text) AND (fingerprint IS NOT NULL))
type_category (type,category)
type_entity_id (type,legacy_wistia_id)
type_title (type,title)
Foreign Keys
fk_rails_... (creator_id => parties.id)
fk_rails_... (poster_image_id => digital_assets.id) ON DELETE => nullify
fk_rails_... (updater_id => parties.id)
fk_rails_... (youtube_thumbnail_image_id => digital_assets.id) ON DELETE => nullify
Constant Summary collapse
- POPULAR_TAGS =
Checkbox labels on image/video forms. Website PDP stills use WYS image profiles on the item—see Image::POPULAR_TAGS_FORM_HINT.
%w[for-product-page for-support-page no-index].freeze
- HIDDEN_TAGS =
%w[installation-plan pdf-thumbnail room-configuration video-poster auto-generated review-avatar].freeze
Constants included from Models::Auditable
Models::Auditable::ALWAYS_IGNORED
Instance Attribute Summary collapse
-
#force_new_slug ⇒ Object
Returns the value of attribute force_new_slug.
-
#refresh_cache ⇒ Object
Returns the value of attribute refresh_cache.
- #title ⇒ Object readonly
- #url ⇒ Object readonly
Has many collapse
- #digital_asset_product_lines ⇒ ActiveRecord::Relation<DigitalAssetProductLine>
- #generated_images ⇒ ActiveRecord::Relation<GeneratedImage>
- #product_lines ⇒ ActiveRecord::Relation<ProductLine>
- #site_maps ⇒ ActiveRecord::Relation<SiteMap>
Methods included from Models::Taggable
Has and belongs to many collapse
- #items ⇒ ActiveRecord::Relation<Item>
- #opportunities ⇒ ActiveRecord::Relation<Opportunity>
- #parties ⇒ ActiveRecord::Relation<Party>
- #product_categories ⇒ ActiveRecord::Relation<ProductCategory>
-
#reviews ⇒ ActiveRecord::Relation<Review>
Legacy associations removed: showcases, showcase_rooms.
Class Method Summary collapse
-
.active ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are active.
-
.all_locales ⇒ Object
Note: all_tags method provided by Models::Taggable concern.
- .available_banner_tags ⇒ Object
- .available_og_image_tags ⇒ Object
-
.available_page_tags ⇒ Object
Generate the available 'for-' page tags for all CMS pages.
- .available_page_tags_with_paths ⇒ Object
-
.banner_tag_for(page_id) ⇒ Object
Build the banner image tag for a given CMS page id.
-
.by_category ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are by category.
-
.by_item_ids ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are by item ids.
-
.by_item_skus ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are by item skus.
-
.by_party_ids ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are by party ids.
-
.by_product_category_id_direct ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are by product category id direct.
-
.by_product_category_id_direct_or_optional ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are by product category id direct or optional.
-
.by_product_line_id ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are by product line id.
-
.by_product_line_id_direct ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are by product line id direct.
-
.by_product_line_path ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are by product line path.
-
.categorized ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are categorized.
-
.exclude_tags ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are exclude tags.
-
.images ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are images.
-
.localized_for ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are localized for.
-
.localized_for_or_not ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are localized for or not.
-
.not_by_party_ids ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are not by party ids.
-
.not_by_product_line_id ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are not by product line id.
-
.not_by_product_line_path ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are not by product line path.
-
.og_image_tag_for(page_id) ⇒ Object
Build the og:image tag for a given CMS page id.
-
.page_tag_for(page_id) ⇒ Object
Build the canonical page tag for a given CMS page id (e.g. "towel-warmer").
- .ransackable_scopes(_auth_object = nil) ⇒ Object
-
.related_to_item_id ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are related to item id.
-
.show_hidden_tags ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are show hidden tags.
-
.tag_presence ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are tag presence.
-
.tagged_with_all ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are tagged with all.
-
.videos ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are videos.
-
.with_product_line_urls ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are with product line urls.
-
.without_product_categories ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are without product categories.
-
.without_product_lines ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are without product lines.
Instance Method Summary collapse
- #alerts ⇒ Object
- #all_my_items ⇒ Object
- #asset_identifier ⇒ Object
- #cross_links_opportunities_to_parties ⇒ Object
- #dimensions ⇒ Object
- #file_basename ⇒ Object
- #is_image? ⇒ Boolean
- #is_video? ⇒ Boolean
- #product_lines_display ⇒ Object
- #product_lines_for_sorting ⇒ Object
- #purge_edge_cache ⇒ Object
- #sanitize_urls ⇒ Object
- #seo_title ⇒ Object
- #should_generate_new_friendly_id? ⇒ Boolean
- #should_sanitize_urls? ⇒ Boolean
- #slug_candidates ⇒ Object
- #tags_display ⇒ Object
- #thumbnail_url ⇒ Object
- #touch_related ⇒ Object
Methods included from Models::Taggable
#add_tag, all_tags, #has_tag?, normalize_tag_names, not_tagged_with, #remove_tag, #tag_list, #tag_list=, #taggable_type_for_tagging, tagged_with, #tags, #tags=, tags_cloud, tags_exclude, tags_include, with_all_tags, with_any_tags, without_all_tags, without_any_tags
Methods included from Models::ItemScopable
by_product_category_id, by_product_category_path, by_product_category_path_exact, by_product_category_url, by_product_category_url_exact, by_product_line_path_full, by_product_line_url, by_product_line_url_full, not_by_product_category_id
Methods included from Models::Auditable
#all_skipped_columns, #audit_reference_data, #creator, #should_not_save_version, #stamp_record, #updater
Methods inherited from ApplicationRecord
ransackable_associations, ransackable_attributes, ransortable_attributes, #to_relation
Methods included from Models::EventPublishable
Instance Attribute Details
#force_new_slug ⇒ Object
Returns the value of attribute force_new_slug.
124 125 126 |
# File 'app/models/digital_asset.rb', line 124 def force_new_slug @force_new_slug end |
#refresh_cache ⇒ Object
Returns the value of attribute refresh_cache.
124 125 126 |
# File 'app/models/digital_asset.rb', line 124 def refresh_cache @refresh_cache end |
#title ⇒ Object (readonly)
142 |
# File 'app/models/digital_asset.rb', line 142 validates :title, presence: true |
#url ⇒ Object (readonly)
143 |
# File 'app/models/digital_asset.rb', line 143 validates :url, uniqueness: { if: :url } |
Class Method Details
.active ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are active. Active Record Scope
155 |
# File 'app/models/digital_asset.rb', line 155 scope :active, -> { where(inactive: false) } |
.all_locales ⇒ Object
Note: all_tags method provided by Models::Taggable concern
360 361 362 |
# File 'app/models/digital_asset.rb', line 360 def self.all_locales pluck(Arel.sql('distinct unnest(locales) as locale')).compact.sort end |
.available_banner_tags ⇒ Object
531 532 533 534 535 |
# File 'app/models/digital_asset.rb', line 531 def self. PagesController.page_ids.reject { |page_id| page_id.start_with?('h-') }.map do |page_id| (page_id) end.uniq.sort end |
.available_og_image_tags ⇒ Object
543 544 545 546 547 |
# File 'app/models/digital_asset.rb', line 543 def self. PagesController.page_ids.reject { |page_id| page_id.start_with?('h-') }.map do |page_id| og_image_tag_for(page_id) end.uniq.sort end |
.available_page_tags ⇒ Object
Generate the available 'for-' page tags for all CMS pages.
Uses the same convention as the cohesive migration:
'for-' + page_id.tr('/', '-').parameterize + '-page'
507 508 509 510 511 |
# File 'app/models/digital_asset.rb', line 507 def self. PagesController.page_ids.reject { |page_id| page_id.start_with?('h-') }.map do |page_id| "for-#{page_id.tr('/', '-').parameterize}-page" end.uniq.sort end |
.available_page_tags_with_paths ⇒ Object
513 514 515 516 517 518 |
# File 'app/models/digital_asset.rb', line 513 def self. PagesController.page_ids.reject { |page_id| page_id.start_with?('h-') }.each_with_object({}) do |page_id, hash| tag = "for-#{page_id.tr('/', '-').parameterize}-page" hash[tag] = "/#{page_id}" end end |
.banner_tag_for(page_id) ⇒ Object
Build the banner image tag for a given CMS page id.
e.g. banner_tag_for("floor-heating/bathroom") => "banner-for-floor-heating-bathroom-page"
527 528 529 |
# File 'app/models/digital_asset.rb', line 527 def self.(page_id) "banner-for-#{page_id.to_s.tr('/', '-').parameterize}-page" end |
.by_category ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are by category. Active Record Scope
212 |
# File 'app/models/digital_asset.rb', line 212 scope :by_category, ->(cat) { where(category: cat) } |
.by_item_ids ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are by item ids. Active Record Scope
213 214 215 216 217 218 |
# File 'app/models/digital_asset.rb', line 213 scope :by_item_ids, ->(*item_ids) { item_ids = [item_ids].flatten.map(&:presence).compact.uniq return none unless item_ids.present? where('exists(select 1 from digital_assets_items dai where dai.item_id IN (?) and dai.digital_asset_id = digital_assets.id)', item_ids) } |
.by_item_skus ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are by item skus. Active Record Scope
263 |
# File 'app/models/digital_asset.rb', line 263 scope :by_item_skus, ->(*item_skus) { joins(:items).where(items: { sku: item_skus }) } |
.by_party_ids ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are by party ids. Active Record Scope
282 283 284 285 286 287 |
# File 'app/models/digital_asset.rb', line 282 scope :by_party_ids, ->(*party_ids) { party_ids = [party_ids].flatten.map(&:presence).compact.uniq return none unless party_ids.present? where('exists(select 1 from digital_assets_parties dap inner join parties p on p.id = dap.party_id where (dap.party_id IN (:party_ids) OR p.customer_id IN (:party_ids)) and dap.digital_asset_id = digital_assets.id)', party_ids: party_ids) } |
.by_product_category_id_direct ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are by product category id direct. Active Record Scope
193 194 195 196 197 198 |
# File 'app/models/digital_asset.rb', line 193 scope :by_product_category_id_direct, ->(*pc_ids) do ids = [pc_ids].flatten return none if ids.empty? where('exists(select 1 from digital_assets_product_categories dapc where dapc.digital_asset_id = digital_assets.id and dapc.product_category_id in (?))', ids) end |
.by_product_category_id_direct_or_optional ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are by product category id direct or optional. Active Record Scope
199 200 201 202 203 204 205 206 207 208 |
# File 'app/models/digital_asset.rb', line 199 scope :by_product_category_id_direct_or_optional, ->(*pc_ids) do ids = [pc_ids].flatten return none if ids.empty? sql = <<-EOS exists(select 1 from digital_assets_product_categories dapc where dapc.digital_asset_id = digital_assets.id and dapc.product_category_id in (?)) OR not exists(select 1 from digital_assets_product_categories dapc where dapc.digital_asset_id = digital_assets.id) EOS where(sql, ids) end |
.by_product_line_id ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are by product line id. Active Record Scope
169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'app/models/digital_asset.rb', line 169 scope :by_product_line_id, ->(*pl_ids) do ids = [pl_ids].flatten.map(&:presence).compact.map(&:to_i).uniq return none if ids.empty? where( 'EXISTS(SELECT 1 FROM digital_asset_product_lines dapl ' \ 'INNER JOIN product_lines pl ON pl.id = dapl.product_line_id ' \ 'WHERE dapl.digital_asset_id = digital_assets.id ' \ 'AND pl.ltree_path_ids <@ ANY(SELECT ltree_path_ids FROM product_lines WHERE id = ANY(ARRAY[?]::integer[])))', ids ) end |
.by_product_line_id_direct ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are by product line id direct. Active Record Scope
163 164 165 166 167 168 |
# File 'app/models/digital_asset.rb', line 163 scope :by_product_line_id_direct, ->(*pl_ids) do ids = [pl_ids].flatten.map(&:presence).compact.uniq return none if ids.empty? where('EXISTS(SELECT 1 FROM digital_asset_product_lines dapl WHERE dapl.digital_asset_id = digital_assets.id AND dapl.product_line_id IN (?))', ids) end |
.by_product_line_path ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are by product line path. Active Record Scope
312 313 314 315 316 317 318 319 320 321 |
# File 'app/models/digital_asset.rb', line 312 scope :by_product_line_path, ->(slug_path) { return all if slug_path.blank? where( 'EXISTS(SELECT 1 FROM digital_asset_product_lines dapl ' \ 'INNER JOIN product_lines pl ON pl.id = dapl.product_line_id ' \ 'WHERE dapl.digital_asset_id = digital_assets.id AND pl.ltree_path_slugs <@ ?)', slug_path ) } |
.categorized ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are categorized. Active Record Scope
296 |
# File 'app/models/digital_asset.rb', line 296 scope :categorized, -> { where.not(category: nil) } |
.exclude_tags ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are exclude tags. Active Record Scope
268 269 270 271 272 273 |
# File 'app/models/digital_asset.rb', line 268 scope :exclude_tags, ->(*tag_names) { tag_names = [tag_names].flatten.map(&:presence).compact.map(&:downcase) return all if tag_names.empty? not_tagged_with(tag_names) } |
.images ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are images. Active Record Scope
297 |
# File 'app/models/digital_asset.rb', line 297 scope :images, -> { where(type: 'Image') } |
.localized_for ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are localized for. Active Record Scope
280 |
# File 'app/models/digital_asset.rb', line 280 scope :localized_for, ->(*locales) { where.overlap(locales: LocaleUtility.locales_and_fallbacks(locales)) } |
.localized_for_or_not ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are localized for or not. Active Record Scope
281 |
# File 'app/models/digital_asset.rb', line 281 scope :localized_for_or_not, ->(*locales) { localized_for(locales).or(where(DigitalAsset[:locales].eq('{}'))) } |
.not_by_party_ids ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are not by party ids. Active Record Scope
290 291 292 293 294 295 |
# File 'app/models/digital_asset.rb', line 290 scope :not_by_party_ids, ->(*party_ids) { party_ids = [party_ids].flatten.map(&:presence).compact.uniq return all unless party_ids.present? where('NOT exists(select 1 from digital_assets_parties dap inner join parties p on p.id = dap.party_id where (dap.party_id IN (:party_ids) OR p.customer_id IN (:party_ids)) and dap.digital_asset_id = digital_assets.id)', party_ids: party_ids) } |
.not_by_product_line_id ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are not by product line id. Active Record Scope
181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'app/models/digital_asset.rb', line 181 scope :not_by_product_line_id, ->(*pl_ids) do ids = [pl_ids].flatten.compact.map(&:to_i) return all if ids.empty? where.not( 'EXISTS(SELECT 1 FROM digital_asset_product_lines dapl ' \ 'INNER JOIN product_lines pl ON pl.id = dapl.product_line_id ' \ 'WHERE dapl.digital_asset_id = digital_assets.id ' \ 'AND pl.ltree_path_ids <@ ANY(SELECT ltree_path_ids FROM product_lines WHERE id = ANY(ARRAY[?]::integer[])))', ids ) end |
.not_by_product_line_path ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are not by product line path. Active Record Scope
325 326 327 328 329 330 331 332 333 334 |
# File 'app/models/digital_asset.rb', line 325 scope :not_by_product_line_path, ->(slug_path) { return all if slug_path.blank? where.not( 'EXISTS(SELECT 1 FROM digital_asset_product_lines dapl ' \ 'INNER JOIN product_lines pl ON pl.id = dapl.product_line_id ' \ 'WHERE dapl.digital_asset_id = digital_assets.id AND pl.ltree_path_slugs <@ ?)', slug_path ) } |
.og_image_tag_for(page_id) ⇒ Object
Build the og:image tag for a given CMS page id.
e.g. og_image_tag_for("floor-heating/bathroom") => "og-image-for-floor-heating-bathroom-page"
539 540 541 |
# File 'app/models/digital_asset.rb', line 539 def self.og_image_tag_for(page_id) "og-image-for-#{page_id.to_s.tr('/', '-').parameterize}-page" end |
.page_tag_for(page_id) ⇒ Object
Build the canonical page tag for a given CMS page id (e.g. "towel-warmer").
521 522 523 |
# File 'app/models/digital_asset.rb', line 521 def self.page_tag_for(page_id) "for-#{page_id.to_s.tr('/', '-').parameterize}-page" end |
.ransackable_scopes(_auth_object = nil) ⇒ Object
352 353 354 355 356 |
# File 'app/models/digital_asset.rb', line 352 def self.ransackable_scopes(_auth_object = nil) %i[keyword_search by_product_line_id by_product_line_path by_product_category_id_direct tag_presence by_party_ids by_item_ids related_to_item_id show_hidden_tags exclude_tags tags_include not_by_product_line_id not_by_party_ids] end |
.related_to_item_id ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are related to item id. Active Record Scope
222 223 224 225 226 227 228 229 230 231 232 233 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 |
# File 'app/models/digital_asset.rb', line 222 scope :related_to_item_id, ->(item_id) { return none if item_id.blank? item = Item.find_by(id: item_id) return none unless item # Get product line path for ltree ancestor matching pl_path = item.primary_pl_path_slugs pc_path = item.pc_path_slugs # Build OR conditions for: # 1. Directly linked to the item # 2. Linked to item's product line or any ancestor (using ltree) # 3. Linked to item's product category or any ancestor (using ltree) conditions = [] binds = {} # Direct item link conditions << 'EXISTS(SELECT 1 FROM digital_assets_items dai WHERE dai.item_id = :item_id AND dai.digital_asset_id = digital_assets.id)' binds[:item_id] = item_id # Product line link (item's PL path is descendant of or equal to the image's PL path) if pl_path.present? conditions << "EXISTS(SELECT 1 FROM digital_asset_product_lines dapl INNER JOIN product_lines pl ON pl.id = dapl.product_line_id WHERE dapl.digital_asset_id = digital_assets.id AND :pl_path <@ pl.ltree_path_slugs)" binds[:pl_path] = pl_path end # Product category link (item's PC path is descendant of or equal to the image's PC path) if pc_path.present? conditions << "EXISTS(SELECT 1 FROM digital_assets_product_categories dapc INNER JOIN product_categories pc ON pc.id = dapc.product_category_id WHERE dapc.digital_asset_id = digital_assets.id AND :pc_path <@ pc.ltree_path_slugs)" binds[:pc_path] = pc_path end where(conditions.join(' OR '), binds) } |
.show_hidden_tags ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are show hidden tags. Active Record Scope
266 |
# File 'app/models/digital_asset.rb', line 266 scope :show_hidden_tags, ->(val) { val.to_b ? all : not_tagged_with(HIDDEN_TAGS) } |
.tag_presence ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are tag presence. Active Record Scope
275 276 277 278 279 |
# File 'app/models/digital_asset.rb', line 275 scope :tag_presence, ->(tag_present) { return if tag_present.blank? tag_present.to_b ? joins(:taggings).distinct : left_joins(:taggings).where(taggings: { id: nil }) } |
.tagged_with_all ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are tagged with all. Active Record Scope
265 |
# File 'app/models/digital_asset.rb', line 265 scope :tagged_with_all, ->(*tag_names) { (*tag_names) } |
.videos ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are videos. Active Record Scope
298 |
# File 'app/models/digital_asset.rb', line 298 scope :videos, -> { where(type: 'Video') } |
.with_product_line_urls ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are with product line urls. Active Record Scope
299 300 301 302 303 304 305 306 307 308 309 |
# File 'app/models/digital_asset.rb', line 299 scope :with_product_line_urls, -> { all.select_append(' ARRAY( select pl.slug_ltree::text from product_lines pl inner join digital_asset_product_lines dapl on dapl.product_line_id = pl.id where dapl.digital_asset_id = digital_assets.id ) as product_line_urls ') } |
.without_product_categories ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are without product categories. Active Record Scope
210 |
# File 'app/models/digital_asset.rb', line 210 scope :without_product_categories, -> { where_not_exists(:product_categories) } |
.without_product_lines ⇒ ActiveRecord::Relation<DigitalAsset>
A relation of DigitalAssets that are without product lines. Active Record Scope
211 |
# File 'app/models/digital_asset.rb', line 211 scope :without_product_lines, -> { where_not_exists(:digital_asset_product_lines) } |
Instance Method Details
#alerts ⇒ Object
364 365 366 367 368 |
# File 'app/models/digital_asset.rb', line 364 def alerts r = [] r << 'SEO Title is too long, keep it at 65 characters or less' if &.size&.> 65 r end |
#all_my_items ⇒ Object
489 490 491 492 493 494 495 496 497 498 499 500 501 502 |
# File 'app/models/digital_asset.rb', line 489 def all_my_items item_ids = items.active.pluck(:id) plids = product_line_ids pcids = product_category_ids if plids.present? && pcids.present? = Item.active.condition_new = .by_product_line_id(plids) if plids.present? = .by_product_category_id(pcids) if pcids.present? item_ids += .pluck(:id) end item_ids.uniq! Item.where(id: item_ids).order(:sku) end |
#asset_identifier ⇒ Object
395 396 397 |
# File 'app/models/digital_asset.rb', line 395 def asset_identifier SecureRandom.base58(6).downcase end |
#cross_links_opportunities_to_parties ⇒ Object
446 447 448 449 |
# File 'app/models/digital_asset.rb', line 446 def cross_links_opportunities_to_parties self.party_ids = party_ids | opportunities.pluck(:customer_id) true end |
#digital_asset_product_lines ⇒ ActiveRecord::Relation<DigitalAssetProductLine>
130 |
# File 'app/models/digital_asset.rb', line 130 has_many :digital_asset_product_lines, -> { order(:position) }, inverse_of: :digital_asset, validate: false |
#dimensions ⇒ Object
415 416 417 418 419 |
# File 'app/models/digital_asset.rb', line 415 def dimensions return unless .present? && .present? "#{} x #{}" end |
#file_basename ⇒ Object
370 371 372 373 374 |
# File 'app/models/digital_asset.rb', line 370 def file_basename return unless .present? File.basename(, '.*') end |
#generated_images ⇒ ActiveRecord::Relation<GeneratedImage>
133 |
# File 'app/models/digital_asset.rb', line 133 has_many :generated_images, foreign_key: :source_image_id, dependent: :destroy, inverse_of: :source_image |
#is_image? ⇒ Boolean
440 441 442 443 444 |
# File 'app/models/digital_asset.rb', line 440 def is_image? return true if type == 'Image' false end |
#is_video? ⇒ Boolean
434 435 436 437 438 |
# File 'app/models/digital_asset.rb', line 434 def is_video? return true if type == 'Video' false end |
#items ⇒ ActiveRecord::Relation<Item>
136 |
# File 'app/models/digital_asset.rb', line 136 has_and_belongs_to_many :items, validate: false |
#opportunities ⇒ ActiveRecord::Relation<Opportunity>
140 |
# File 'app/models/digital_asset.rb', line 140 has_and_belongs_to_many :opportunities, validate: false, inverse_of: :digital_assets |
#parties ⇒ ActiveRecord::Relation<Party>
137 |
# File 'app/models/digital_asset.rb', line 137 has_and_belongs_to_many :parties, validate: false |
#product_categories ⇒ ActiveRecord::Relation<ProductCategory>
135 |
# File 'app/models/digital_asset.rb', line 135 has_and_belongs_to_many :product_categories, validate: false |
#product_lines ⇒ ActiveRecord::Relation<ProductLine>
131 |
# File 'app/models/digital_asset.rb', line 131 has_many :product_lines, through: :digital_asset_product_lines, validate: false |
#product_lines_display ⇒ Object
411 412 413 |
# File 'app/models/digital_asset.rb', line 411 def product_lines_display product_lines.collect { |pl| pl.name }.join(', ') end |
#product_lines_for_sorting ⇒ Object
403 404 405 |
# File 'app/models/digital_asset.rb', line 403 def product_lines_for_sorting product_lines.collect { |pl| pl.self_and_ancestors }.flatten.collect { |pl| pl.slug_ltree }.map { |slt| "product-line-#{slt}" }.join(' ') end |
#purge_edge_cache ⇒ Object
451 452 453 454 |
# File 'app/models/digital_asset.rb', line 451 def purge_edge_cache urls = site_maps.map(&:url) EdgeCacheWorker.perform_async('urls' => urls) if urls.present? end |
#reviews ⇒ ActiveRecord::Relation<Review>
Legacy associations removed: showcases, showcase_rooms
139 |
# File 'app/models/digital_asset.rb', line 139 has_and_belongs_to_many :reviews, validate: false |
#sanitize_urls ⇒ Object
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 |
# File 'app/models/digital_asset.rb', line 456 def sanitize_urls sd = Seo::DeparameterizeLinks.new ld = Seo::HtmlLinkSanitizer.new imgf = Seo::ImageMissingSizeFiller.new if .present? logger.info "Sanitizing urls in expanded_description for digital asset:#{id}" h = h = ld.process(h).html_out h = sd.process(h).html_out h = imgf.process(h).html_out # Nokogiri URL-encodes spaces in href attributes, corrupting {{ locale }} to {{%20locale%20}}. h = h.gsub(/\{\{%20([\w_]+)%20\}\}/) { "{{#{Regexp.last_match(1)}}}" } self. = h end return unless transcript.present? logger.info "Sanitizing urls in transcript for digital asset:#{id}" h = transcript h = ld.process(h).html_out h = sd.process(h).html_out h = imgf.process(h).html_out # Nokogiri URL-encodes spaces in href attributes, corrupting {{ locale }} to {{%20locale%20}}. h = h.gsub(/\{\{%20([\w_]+)%20\}\}/) { "{{#{Regexp.last_match(1)}}}" } self.transcript = h end |
#seo_title ⇒ Object
376 377 378 379 |
# File 'app/models/digital_asset.rb', line 376 def seo_title s = .presence || title.presence || file_basename s&.first(133) end |
#should_generate_new_friendly_id? ⇒ Boolean
399 400 401 |
# File 'app/models/digital_asset.rb', line 399 def should_generate_new_friendly_id? || title_changed? || || url_changed? || force_new_slug.to_b end |
#should_sanitize_urls? ⇒ Boolean
484 485 486 487 |
# File 'app/models/digital_asset.rb', line 484 def should_sanitize_urls? ( && .present?) || (transcript_changed? && transcript.present?) end |
#site_maps ⇒ ActiveRecord::Relation<SiteMap>
132 |
# File 'app/models/digital_asset.rb', line 132 has_many :site_maps, as: :resource, dependent: :destroy |
#slug_candidates ⇒ Object
381 382 383 384 385 386 387 388 389 |
# File 'app/models/digital_asset.rb', line 381 def slug_candidates sc = [] if url.present? sc << [:url] sc << %i[url asset_identifier] end sc << %i[seo_title asset_identifier] sc end |
#tags_display ⇒ Object
407 408 409 |
# File 'app/models/digital_asset.rb', line 407 def .join(', ') end |
#thumbnail_url ⇒ Object
391 392 393 |
# File 'app/models/digital_asset.rb', line 391 def thumbnail_url # Placeholder, implement in specialized class end |
#touch_related ⇒ Object
421 422 423 424 425 426 427 428 429 430 431 432 |
# File 'app/models/digital_asset.rb', line 421 def return unless @refresh_cache.to_b if product_line_ids.present? paths = ProductLine.where(id: product_line_ids).pluck(:ltree_path_ids).compact unless paths.empty? ProductLine.where(ProductLine[:ltree_path_ids].ltree_descendant(paths)) .find_each(&:touch) end end items.find_each(&:touch) end |