Skip to content

Instantly share code, notes, and snippets.

@hungmi
Last active June 16, 2021 17:39
Show Gist options
  • Save hungmi/adc35a9fab2064fc434fb951df9eec80 to your computer and use it in GitHub Desktop.
Save hungmi/adc35a9fab2064fc434fb951df9eec80 to your computer and use it in GitHub Desktop.
Rails ActionText: support prism syntax highlight code blocks. And transform <action-text-attachment/> to <img/> to work with any frontend.
# lib/action_text_parser.rb
# require 'action_text_parser' in application.rb
class ActionTextParser
def self.run(action_text_record)
html = action_text_record.body.to_html
nodes = Nokogiri::HTML::DocumentFragment.parse html
nodes = self.parse_attachments(nodes)
nodes = self.parse_code(nodes)
nodes.to_html
end
def self.parse_attachments(nodes)
# transform every <action-text-attachment/> to <img/>
nodes.css('action-text-attachment').map do |attachment|
src = attachment.attributes['url'].value
width = attachment.attributes['width'].value
height = attachment.attributes['height'].value
alt = attachment.attributes['caption'].try(:value) || attachment.attributes['filename'].try(:value)
attachment.swap("<img src='#{src}' width='#{width}' height='#{height}' alt='#{alt}' title='#{alt}' />")
end
nodes
end
def self.parse_code(nodes)
# transform <pre>...</pre> to "<pre><code class='#{lang-xxx}'>...</code></pre>"
nodes.css('pre').map do |pre|
lang_class = pre.content.split("\n")[-1].strip
if lang_class.present? && lang_class[/lang\-*/].present?
pre.swap("<pre><code class='#{lang_class}'>#{pre.content.strip.gsub(lang_class, '')}</code></pre>")
end
end
nodes
end
end
class Api::V1::PostsController < ApplicationController
def show
@post = Post.find_by_id(params[:id])
if @post
render json: { content_html: ActionTextParser.run(@post.content) }
end
end
end
<!-- /posts/show.html.erb -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/themes/prism-okaidia.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/plugins/line-numbers/prism-line-numbers.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/components/prism-core.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/plugins/autoloader/prism-autoloader.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.17.1/plugins/line-numbers/prism-line-numbers.min.js"></script>
<%= raw ActionTextParser.run @post.content %>
@ajessee
Copy link

ajessee commented Jun 16, 2021

Nice! Glad to see my post could be helpful to someone else. Thanks for tagging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment