So I was looking for a method to serve attachments uploaded by users in the Rails Active Storage. Regardless of where these are served from, I needed a way to insert them into the document.
I read This article by Salazar explaining how to serve SVG icon packs and I realized that with a small tweak, I can use it for my case.
def show_svg(attachment, options = {})
return if !attachment.content_type.include?('svg')
attachment.open do |file|
content = file.read
doc = Nokogiri::HTML::DocumentFragment.parse content
svg = doc.at_css 'svg'
# for security
doc.search('script').each do |src|
src.remove
end
options.each { |attr, value| svg[attr.to_s] = value }
doc.to_html.html_safe
end
end
I added a few security measure to ensure that we are only displaying SVG, I’m making sure that only this type of file is served and also just in case, stripping <script> tags.
Try it:
<svg>
<script>alert(1)</script>
</svg>
Once that method is set up, I can just pass in the attachment in the view. get_image_url
is just a custom method to retrieve a link to this image.
<% if post.image.content_type.include? 'svg' %>
<%= show_svg post.image %>
<% else %>
<%= image_tag post.get_image_url(variant: :small) %>
<% end %>