如何在Rails(ActionText)的Trix编辑器中允许iframe或原始HTML内容?
嗨,我来帮你解决这个问题!不用急着切换到其他编辑器,Trix + ActionText完全可以实现你要的功能,而且能做到干净又安全——毕竟你已经确认只有可信管理员使用这个表单,我们只要针对性放开权限并做好过滤就行。
整体思路
核心要做两件事:一是让Trix编辑器在粘贴时不转义你允许的iframe内容,二是让Rails后端处理ActionText内容时,不会把这些iframe过滤掉,同时只保留来自YouTube/Vimeo的合法链接。
第一步:修改Trix的前端粘贴行为
Trix默认会转义所有粘贴的HTML,所以我们需要给编辑器加一个粘贴事件监听器,手动处理iframe内容:
在你的JavaScript控制器文件里(比如app/javascript/controllers/action_text_controller.js)添加这段代码:
document.addEventListener("trix-paste", function(event) { const clipboardHtml = event.clipboardData.getData("text/html"); if (!clipboardHtml) return; // 解析粘贴的HTML内容 const parser = new DOMParser(); const doc = parser.parseFromString(clipboardHtml, "text/html"); const iframes = doc.querySelectorAll("iframe"); if (iframes.length === 0) return; // 阻止默认粘贴行为,避免Trix转义内容 event.preventDefault(); const editor = event.target.editor; iframes.forEach(iframe => { const src = iframe.src; // 只保留YouTube和Vimeo的iframe if (src.includes("youtube.com/embed") || src.includes("player.vimeo.com/video")) { editor.insertHTML(iframe.outerHTML); } }); });
这段代码会在用户粘贴HTML时,自动提取其中的iframe,检查来源是否是你允许的平台,符合条件的就直接插入编辑器,不会被转义。
第二步:自定义ActionText的内容清理器
ActionText默认会过滤掉iframe这类标签,所以我们需要自定义一个清理规则,允许iframe同时限制它的合法来源:
- 在
app/lib目录下创建custom_action_text_sanitizer.rb文件:
class CustomActionTextSanitizer < Rails::Html::Sanitizer def initialize super @whitelist_sanitizer = Rails::Html::WhiteListSanitizer.new( # 保留默认允许的标签,再加上iframe tags: Rails::Html::WhiteListSanitizer.allowed_tags + %w[iframe], # 给iframe添加允许的属性 attributes: Rails::Html::WhiteListSanitizer.allowed_attributes.merge( "iframe" => %w[src width height frameborder allowfullscreen] ) ) end def sanitize(html, options = {}) # 先通过默认白名单过滤 sanitized_html = @whitelist_sanitizer.sanitize(html, options) # 再进一步过滤iframe的src,只保留合法域名 doc = Nokogiri::HTML.fragment(sanitized_html) doc.css("iframe").each do |iframe| src = iframe["src"] unless src&.match?(/\Ahttps?:\/\/(www\.youtube\.com\/embed|player\.vimeo\.com\/video)/) iframe.remove end end doc.to_html end end
- 在
config/initializers/action_text.rb中配置ActionText使用这个自定义清理器:
Rails.application.config.action_text.content_sanitizer = CustomActionTextSanitizer.new
第三步:验证渲染效果
做完上面的配置后,当管理员粘贴合法的YouTube/Vimeo iframe HTML时,Trix会直接插入正确的内容,后端也会保留这个iframe并限制来源,最后在视图中用<%= @your_model.your_rich_text_field %>渲染时,就会正常显示视频播放器,而不是纯文本。
要不要切换编辑器?
完全没必要!上面的方案已经是干净且安全的了:前端拦截了非法内容,后端又做了双重过滤,既满足了你的需求,又遵循了Rails的安全规范。如果之后需要扩展允许的标签,只要在sanitizer里添加对应的规则就行。
内容来源于stack exchange

