Skip to Content Skip to Search

Action Text Attachment

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..."
Methods
A
C
F
N
T
W

Constants

ATTRIBUTES = %w( sgid content-type url href filename filesize width height previewable presentation caption alt content ).freeze
 

Attributes

[R] attachable
[R] node

Class Public methods

fragment_by_canonicalizing_attachments(content)

# File actiontext/lib/action_text/attachment.rb, line 28
def fragment_by_canonicalizing_attachments(content)
  fragment_by_minifying_attachments(fragment_by_converting_editor_attachments(content))
end

from_attachable(attachable, attributes = {})

# File actiontext/lib/action_text/attachment.rb, line 40
def from_attachable(attachable, attributes = {})
  if node = node_from_attributes(attachable.to_rich_text_attributes(attributes))
    new(node, attachable)
  end
end

from_attachables(attachables)

# File actiontext/lib/action_text/attachment.rb, line 36
def from_attachables(attachables)
  Array(attachables).filter_map { |attachable| from_attachable(attachable) }
end

from_attributes(attributes, attachable = nil)

# File actiontext/lib/action_text/attachment.rb, line 46
def from_attributes(attributes, attachable = nil)
  if node = node_from_attributes(attributes)
    from_node(node, attachable)
  end
end

from_node(node, attachable = nil)

# File actiontext/lib/action_text/attachment.rb, line 32
def from_node(node, attachable = nil)
  new(node, attachable || ActionText::Attachable.from_node(node))
end

new(node, attachable)

# File actiontext/lib/action_text/attachment.rb, line 69
def initialize(node, attachable)
  @node = node
  @attachable = attachable
end

Instance Public methods

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"
# File actiontext/lib/action_text/attachment.rb, line 87
def alt
  node_attributes["alt"].presence
end

caption()

# File actiontext/lib/action_text/attachment.rb, line 74
def caption
  node_attributes["caption"].presence
end

full_attributes()

# File actiontext/lib/action_text/attachment.rb, line 91
def full_attributes
  node_attributes.merge(attachable_attributes).merge(sgid_attributes)
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...
# File actiontext/lib/action_text/attachment.rb, line 207
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) # => "[report.pdf](http://example.com/rails/active_storage/blobs/...)"

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 # => "[@Javan](http://example.com/people/1)"

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
# File actiontext/lib/action_text/attachment.rb, line 194
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_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]"
# File actiontext/lib/action_text/attachment.rb, line 124
def to_plain_text
  if respond_to?(:attachable_plain_text_representation)
    attachable_plain_text_representation(caption)
  else
    caption.to_s
  end
end

to_s()

# File actiontext/lib/action_text/attachment.rb, line 211
def to_s
  to_html
end

with_full_attributes()

# File actiontext/lib/action_text/attachment.rb, line 95
def with_full_attributes
  self.class.from_attributes(full_attributes, attachable)
end