123456789_123456789_123456789_123456789_123456789_

Class: ActionText::Content

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Instance Chain:
self, Rendering, Serialization, ContentHelper
Inherits: Object
Defined in: actiontext/lib/action_text/content.rb

Overview

The Content class wraps an HTML fragment to add support for parsing, rendering and serialization. It can be used to extract links and attachments, convert the fragment to plain text, or serialize the fragment to the database.

The ActionText::RichText record serializes the body attribute as Content.

class Message < ActiveRecord::Base
  has_rich_text :content
end

message = Message.create!(content: "<h1>Funny times!</h1>")
body = message.content.body # => #<ActionText::Content "<div class=\"trix-conte...">
body.to_s # => "<h1>Funny times!</h1>"
body.to_plain_text # => "Funny times!"

Rendering - Attributes & Methods

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Serialization - Included

Constructor Details

.new(content = nil, options = {}) ⇒ Content

[ GitHub ]

  
# File 'actiontext/lib/action_text/content.rb', line 41

def initialize(content = nil, options = {})
  options.with_defaults! canonicalize: true

  if options[:canonicalize]
    @fragment = self.class.fragment_by_canonicalizing_content(content)
  else
    @fragment = ActionText::Fragment.wrap(content)
  end
end

Class Method Details

.fragment_by_canonicalizing_content(content)

[ GitHub ]

Instance Attribute Details

#deconstruct (readonly)

[ GitHub ]

  
# File 'actiontext/lib/action_text/content.rb', line 29

delegate :deconstruct, to: :fragment

#fragment (readonly)

[ GitHub ]

  
# File 'actiontext/lib/action_text/content.rb', line 27

attr_reader :fragment

#html_safe (readonly)

[ GitHub ]

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

delegate :blank?, :empty?, :html_safe, :present?, to: :to_html # Delegating to to_html to avoid including the layout

#render (readonly)

[ GitHub ]

  
# File 'actiontext/lib/action_text/rendering.rb', line 13

delegate :render, to: :class

Instance Method Details

#==(other)

[ GitHub ]

  
# File 'actiontext/lib/action_text/content.rb', line 199

def ==(other)
  if self.class == other.class
    to_html == other.to_html
  elsif other.is_a?(self.class)
    to_s == other.to_s
  end
end

#append_attachables(attachables)

[ GitHub ]

  
# File 'actiontext/lib/action_text/content.rb', line 94

def append_attachables(attachables)
  attachments = ActionText::Attachment.from_attachables(attachables)
  self.class.new([self.to_s.presence, *attachments].compact.join("\n"))
end

#as_json

[ GitHub ]

  
# File 'actiontext/lib/action_text/content.rb', line 191

def as_json(*)
  to_html
end

#attachables

Extracts Attachable objects from the HTML fragment:

attachable = ActiveStorage::Blob.first
html = %Q(<action-text-attachment sgid="#{attachable.attachable_sgid}" caption="Captioned"></action-text-attachment>)
content = ActionText::Content.new(html)
content.attachables # => [attachable]
[ GitHub ]

  
# File 'actiontext/lib/action_text/content.rb', line 88

def attachables
  @attachables ||= attachment_nodes.map do |node|
    ActionText::Attachable.from_node(node)
  end
end

#attachment_for_node(node, with_full_attributes: true) (private)

[ GitHub ]

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

def attachment_for_node(node, with_full_attributes: true)
  attachment = ActionText::Attachment.from_node(node)
  with_full_attributes ? attachment.with_full_attributes : attachment
end

#attachment_galleries

[ GitHub ]

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

def attachment_galleries
  @attachment_galleries ||= attachment_gallery_nodes.map do |node|
    attachment_gallery_for_node(node)
  end
end

#attachment_nodes (private)

[ GitHub ]

  
# File 'actiontext/lib/action_text/content.rb', line 208

def attachment_nodes
  @attachment_nodes ||= fragment.find_all(ActionText::Attachment.tag_name)
end

#attachments

Extracts Attachment objects from the HTML fragment:

attachable = ActiveStorage::Blob.first
html = %Q(<action-text-attachment sgid="#{attachable.attachable_sgid}" caption="Captioned"></action-text-attachment>)
content = ActionText::Content.new(html)
content.attachments # => [#<ActionText::Attachment attachable=#<ActiveStorage::Blob...
[ GitHub ]

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

def attachments
  @attachments ||= attachment_nodes.map do |node|
    attachment_for_node(node)
  end
end

#blank?Boolean

[ GitHub ]

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

delegate :blank?, :empty?, :html_safe, :present?, to: :to_html # Delegating to to_html to avoid including the layout

#empty?Boolean

[ GitHub ]

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

delegate :blank?, :empty?, :html_safe, :present?, to: :to_html # Delegating to to_html to avoid including the layout

#inspect

[ GitHub ]

  
# File 'actiontext/lib/action_text/content.rb', line 195

def inspect
  "#<#{self.class.name} #{to_html.truncate(25).inspect}>"
end

#present?Boolean

[ GitHub ]

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

delegate :blank?, :empty?, :html_safe, :present?, to: :to_html # Delegating to to_html to avoid including the layout

#render_attachment_galleries(&block)

[ GitHub ]

  
# File 'actiontext/lib/action_text/content.rb', line 110

def render_attachment_galleries(&block)
  content = ActionText::AttachmentGallery.fragment_by_replacing_attachment_gallery_nodes(fragment) do |node|
    block.call(attachment_gallery_for_node(node))
  end
  self.class.new(content, canonicalize: false)
end

#render_attachments(**options, &block)

[ GitHub ]

  
# File 'actiontext/lib/action_text/content.rb', line 99

def render_attachments(**options, &block)
  content = fragment.replace(ActionText::Attachment.tag_name) do |node|
    if node.key?("content")
      sanitized_content = sanitize_content_attachment(node.remove_attribute("content").to_s)
      node["content"] = sanitized_content if sanitized_content.present?
    end
    block.call(attachment_for_node(node, **options))
  end
  self.class.new(content, canonicalize: false)
end

#to_editor_html

This method is for internal use only.
[ GitHub ]

  
# File 'actiontext/lib/action_text/content.rb', line 161

def to_editor_html # :nodoc:
  canonical_content = render_attachments(&:to_editor_attachment)
  canonical_fragment = Fragment.wrap(canonical_content.fragment)

  RichText.editor.as_editable(canonical_fragment).to_html
end

#to_html

[ GitHub ]

  
# File 'actiontext/lib/action_text/content.rb', line 168

def to_html
  fragment.to_html
end

#to_markdown(attachment_links: false)

Returns a Markdown version of the markup contained by the content.

content = ActionText::Content.new("<h1>Funny times!</h1>")
content.to_markdown # => "# Funny times!"

content = ActionText::Content.new("<p>Hello <strong>world</strong></p>")
content.to_markdown # => "Hello **world**"

When attachment_links is true, ::ActiveStorage blob attachments generate Markdown links with URLs. This requires a rendering context (e.g., controller or mailer action) and will raise if URL generation fails.

NOTE: that the returned string is not HTML safe and should not be rendered in browsers without additional sanitization.

[ GitHub ]

  
# File 'actiontext/lib/action_text/content.rb', line 150

def to_markdown(attachment_links: false)
  render_attachments(with_full_attributes: false) { |attachment|
    ActionText::MarkdownConversion.render_attachment(attachment, attachment_links: attachment_links)
  }.fragment.to_markdown
end

#to_partial_path

[ GitHub ]

  
# File 'actiontext/lib/action_text/content.rb', line 176

def to_partial_path
  "action_text/contents/content"
end

#to_plain_text

Returns a plain-text version of the markup contained by the content, with tags removed but HTML entities encoded.

content = ActionText::Content.new("<h1>Funny times!</h1>")
content.to_plain_text # => "Funny times!"

content = ActionText::Content.new("<div onclick='action()'>safe<script>unsafe</script></div>")
content.to_plain_text # => "safe"

NOTE: that the returned string is not HTML safe and should not be rendered in browsers without additional sanitization.

content = ActionText::Content.new("&lt;script&gt;alert()&lt;/script&gt;")
content.to_plain_text # => "<script>alert()</script>"
ActionText::ContentHelper.sanitizer.sanitize(content.to_plain_text) # => ""
[ GitHub ]

  
# File 'actiontext/lib/action_text/content.rb', line 132

def to_plain_text
  render_attachments(with_full_attributes: false, &:to_plain_text).fragment.to_plain_text
end

#to_rendered_html_with_layout

[ GitHub ]

  
# File 'actiontext/lib/action_text/content.rb', line 172

def to_rendered_html_with_layout
  render layout: "action_text/contents/content", partial: to_partial_path, formats: :html, locals: { content: self }
end

#to_s

Safely transforms Content into an HTML String.

content = ActionText::Content.new("<h1>Funny times!</h1>")
content.to_s # => "<h1>Funny times!</h1>"

content = ActionText::Content.new("<div onclick='action()'>safe<script>unsafe</script></div>")
content.to_s # => "<div>safeunsafe</div>"
[ GitHub ]

  
# File 'actiontext/lib/action_text/content.rb', line 187

def to_s
  to_rendered_html_with_layout
end

#to_trix_html

[ GitHub ]

  
# File 'actiontext/lib/action_text/content.rb', line 156

def to_trix_html
  to_editor_html
end