123456789_123456789_123456789_123456789_123456789_

Class: ActionText::Content

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Instance Chain:
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

Constructor Details

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

[ GitHub ]

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

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 ]

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

def fragment_by_canonicalizing_content(content)
  fragment = ActionText::Attachment.fragment_by_canonicalizing_attachments(content)
  fragment = ActionText::AttachmentGallery.fragment_by_canonicalizing_attachment_galleries(fragment)
  fragment
end

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 14

delegate :render, to: :class

Instance Method Details

#==(other)

[ GitHub ]

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

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 93

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 157

def as_json(*)
  to_html
end

#attachables

Extracts Attachables 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 87

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 182

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 71

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 174

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

#attachments

Extracts Attachments 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 65

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 161

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 105

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 98

def render_attachments(**options, &block)
  content = fragment.replace(ActionText::Attachment.tag_name) do |node|
    block.call(attachment_for_node(node, **options))
  end
  self.class.new(content, canonicalize: false)
end

#to_html

[ GitHub ]

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

def to_html
  fragment.to_html
end

#to_partial_path

[ GitHub ]

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

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 # => "safeunsafe"

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

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

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

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 138

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(content: "<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 153

def to_s
  to_rendered_html_with_layout
end

#to_trix_html

[ GitHub ]

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

def to_trix_html
  render_attachments(&:to_trix_attachment).to_html
end