123456789_123456789_123456789_123456789_123456789_

Class: ActionText::Attachment

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Instance Chain:
Inherits: Object
Defined in: actiontext/lib/action_text/attachment.rb

Overview

Attachments serialize attachables to HTML or plain text.

class Person < ApplicationRecord
  include ActionText::Attachable
end

attachable = Person.create! name: "Javan"
attachment = ActionText::Attachment.from_attachable(attachable)
attachment.to_html # => "<action-text-attachment sgid=\"BAh7CEk..."

Constant Summary

Class Attribute Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Attachments::TrixConversion - Included

Attachments::Caching - Included

Attachments::Conversion - Included

Constructor Details

.new(node, attachable) ⇒ Attachment

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 67

def initialize(node, attachable)
  @node = node
  @attachable = attachable
end

Class Attribute Details

.tag_name (rw) Also known as: #tag_name

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 21

mattr_accessor :tag_name, default: "action-text-attachment"

Class Method Details

.fragment_by_canonicalizing_attachments(content)

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 26

def fragment_by_canonicalizing_attachments(content)
  fragment_by_minifying_attachments(fragment_by_converting_editor_attachments(content))
end

.from_attachable(attachable, attributes = {})

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 38

def from_attachable(attachable, attributes = {})
  if node = node_from_attributes(attachable.to_rich_text_attributes(attributes))
    new(node, attachable)
  end
end

.from_attachables(attachables)

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 34

def from_attachables(attachables)
  Array(attachables).filter_map { |attachable| from_attachable(attachable) }
end

.from_attributes(attributes, attachable = nil)

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 44

def from_attributes(attributes, attachable = nil)
  if node = node_from_attributes(attributes)
    from_node(node, attachable)
  end
end

.from_node(node, attachable = nil)

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 30

def from_node(node, attachable = nil)
  new(node, attachable || ActionText::Attachable.from_node(node))
end

.node_from_attributes(attributes) (private)

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 51

def node_from_attributes(attributes)
  if attributes = process_attributes(attributes).presence
    ActionText::HtmlConversion.create_element(tag_name, attributes)
  end
end

.process_attributes(attributes) (private)

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 57

def process_attributes(attributes)
  attributes.transform_keys { |key| key.to_s.underscore.dasherize }.slice(*ATTRIBUTES)
end

Instance Attribute Details

#attachable (readonly)

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 62

attr_reader :node, :attachable

#node (readonly)

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 62

attr_reader :node, :attachable

#tag_name (rw)

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 21

mattr_accessor :tag_name, default: "action-text-attachment"

Instance Method Details

#alt

Returns the alternative text describing the attachment, used as the alt attribute when rendering an image.

A caption is shown alongside the attachment, whereas alternative text describes it for people who cannot see it. They serve different purposes, so an attachment may have either, both, or neither.

attachment = ActionText::Attachment.from_attachable(attachable, alt: "A racecar on a track")
attachment.alt # => "A racecar on a track"
[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 85

def alt
  node_attributes["alt"].presence
end

#attachable_attributes (private)

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 224

def attachable_attributes
  @attachable_attributes ||= (attachable.try(:to_rich_text_attributes) || {}).stringify_keys
end

#caption

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 72

def caption
  node_attributes["caption"].presence
end

#full_attributes

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 89

def full_attributes
  node_attributes.merge(attachable_attributes).merge(sgid_attributes)
end

#instance_variables_to_inspect (private)

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 216

def instance_variables_to_inspect
  [:@attachable].freeze
end

#node_attributes (private)

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 220

def node_attributes
  @node_attributes ||= ATTRIBUTES.to_h { |name| [ name.underscore, node[name] ] }.compact
end

#sgid_attributes (private)

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 228

def sgid_attributes
  @sgid_attributes ||= node_attributes.slice("sgid").presence || attachable_attributes.slice("sgid")
end

#to_html

Converts the attachment to HTML.

attachable = Person.create! name: "Javan"
attachment = ActionText::Attachment.from_attachable(attachable)
attachment.to_html # => "<action-text-attachment sgid=\"BAh7CEk...
[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 205

def to_html
  HtmlConversion.node_to_html(node)
end

#to_markdown(attachment_links: false)

Converts the attachment to Markdown.

By default, ::ActiveStorage blob attachments render as bracketed text:

attachable = ActiveStorage::Blob.find_by filename: "racecar.jpg"
attachment = ActionText::Attachment.from_attachable(attachable)
attachment.to_markdown # => "\\[racecar.jpg\\]"

Use the #caption when set:

attachment = ActionText::Attachment.from_attachable(attachable, caption: "Vroom vroom")
attachment.to_markdown # => "\\[Vroom vroom\\]"

When attachment_links is true and a rendering context is available (e.g., controller or mailer action), ::ActiveStorage blob attachments generate Markdown links with URLs.

# Image blob
attachment.to_markdown(attachment_links: true) # => "![racecar.jpg](http://example.com/rails/active_storage/blobs/...)"

# Non-image blob
attachment.to_markdown(attachment_links: true) # => <a href='http://example.com/rails/active_storage/blobs/...'>report.pdf</a>"

Remote images always render as Markdown image links when the URL scheme is allowed:

content = ActionText::Content.new('<action-text-attachment content-type="image/jpeg" url="https://example.com/photo.jpg" caption="A photo"></action-text-attachment>')
content.to_markdown # => "![A photo](https://example.com/photo.jpg)"

Remote images with a disallowed URL scheme render as escaped bracketed text:

content = ActionText::Content.new('<action-text-attachment content-type="image/jpeg" url="data:text/html,PAYLOAD" caption="Click"></action-text-attachment>')
content.to_markdown # => "\\[Click\\]"

The presentation can be overridden by implementing the attachable_markdown_representation method:

class Person < ApplicationRecord
  include ActionText::Attachable

  def attachable_markdown_representation(caption, attachment_links: false)
    ActionText::MarkdownConversion.markdown_link("@#{name}", Rails.application.routes.url_helpers.person_url(self))
  end
end

attachable = Person.create! name: "Javan"
attachment = ActionText::Attachment.from_attachable(attachable)
attachment.to_markdown # => <a href='http://example.com/people/1'>@Javan</a>"

NOTE: When overriding attachable_markdown_representation, the #caption parameter is derived from the document and should be considered untrusted, so an implementation must escape any caption-derived text with ActionText::MarkdownConversion.escape_markdown_text, or pass it through ActionText::MarkdownConversion.markdown_link, which escapes the link title and rejects disallowed URI schemes. Returning the caption unchanged lets a stored rich text body inject arbitrary Markdown.

class Person < ApplicationRecord
  include ActionText::Attachable

  def attachable_markdown_representation(caption, attachment_links: false)
    ActionText::MarkdownConversion.escape_markdown_text(caption.to_s) # take care to escape the caption
  end
end
[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 192

def to_markdown(attachment_links: false)
  if respond_to?(:attachable_markdown_representation)
    attachable_markdown_representation(caption, attachment_links: attachment_links)
  else
    MarkdownConversion.escape_markdown_text(caption.to_s)
  end
end

#to_param

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 64

delegate :to_param, to: :attachable

#to_plain_text

Converts the attachment to plain text.

attachable = ActiveStorage::Blob.find_by filename: "racecar.jpg"
attachment = ActionText::Attachment.from_attachable(attachable)
attachment.to_plain_text # => "[racecar.jpg]"

Use the #caption when set:

attachment = ActionText::Attachment.from_attachable(attachable, caption: "Vroom vroom")
attachment.to_plain_text # => "[Vroom vroom]"

The presentation can be overridden by implementing the attachable_plain_text_representation method:

class Person < ApplicationRecord
  include ActionText::Attachable

  def attachable_plain_text_representation(caption)
    "[#{name}]"
  end
end

attachable = Person.create! name: "Javan"
attachment = ActionText::Attachment.from_attachable(attachable)
attachment.to_plain_text # => "[Javan]"
[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 122

def to_plain_text
  if respond_to?(:attachable_plain_text_representation)
    attachable_plain_text_representation(caption)
  else
    caption.to_s
  end
end

#to_s

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 209

def to_s
  to_html
end

#with_full_attributes

[ GitHub ]

  
# File 'actiontext/lib/action_text/attachment.rb', line 93

def with_full_attributes
  self.class.from_attributes(full_attributes, attachable)
end