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 69

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 23

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 28

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 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)

[ GitHub ]

  
# 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)

[ GitHub ]

  
# 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)

[ GitHub ]

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

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 53

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 59

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 64

attr_reader :node, :attachable

#node (readonly)

[ GitHub ]

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

attr_reader :node, :attachable

#tag_name (rw)

[ GitHub ]

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

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 87

def alt
  node_attributes["alt"].presence
end

#attachable_attributes (private)

[ GitHub ]

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

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

#caption

[ GitHub ]

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

def caption
  node_attributes["caption"].presence
end

#full_attributes

[ GitHub ]

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

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 218

def instance_variables_to_inspect
  [:@attachable].freeze
end

#node_attributes (private)

[ GitHub ]

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

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 230

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 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) # => <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 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_param

[ GitHub ]

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

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 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

[ GitHub ]

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

def to_s
  to_html
end

#with_full_attributes

[ GitHub ]

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

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