Rails 8中ActionText生成文章目录功能失效问题求助
问题分析
你遇到的核心问题是ActionText会自动过滤自定义HTML属性,并且直接赋值HTML字符串的方式会触发ActionText的重新解析流程,导致你添加的id属性被丢弃。具体原因包括:
- ActionText默认的内容过滤器会移除未被允许的标签属性,
id不在h1标签的默认允许列表中 - 直接通过
self.body = html_string赋值时,ActionText会重新解析HTML并过滤属性,覆盖你修改后的内容 - 之前的实现错误地操作了渲染后的HTML(如
to_trix_html),而非ActionText存储的原始内容
解决方案
步骤1:配置ActionText允许h1标签的id属性
在config/initializers/action_text.rb中添加以下配置,让ActionText保留h1标签的id属性:
Rails.application.config.action_text.content_filter.allowlist do |allowlist| allowlist.add 'h1', attributes: ['id'] end
修改后重启Rails服务器,让配置生效。
步骤2:修正模型中的处理逻辑
直接操作ActionText的原始内容,避免重新解析导致属性丢失,同时优化目录生成逻辑:
class Post < ApplicationRecord has_rich_text :body has_rich_text :toc before_save :process_body private def process_body return if body.blank? || body.content.blank? # 解析ActionText存储的原始内容,而非渲染后的HTML doc = Nokogiri::HTML::DocumentFragment.parse(body.content) headings = doc.css("h1") return if headings.empty? toc_items = [] headings.each_with_index do |heading, index| # 生成唯一id(避免重复标题导致锚点冲突) base_id = heading.text.strip.gsub(/\s+/, "-").downcase unique_id = "#{base_id}-#{index + 1}" heading["id"] = unique_id toc_items << "<li><a href='##{unique_id}'>#{heading.text.strip}</a></li>" end # 直接更新body的原始内容,而非重新赋值整个RichText对象 body.content = doc.to_html # 生成并赋值目录内容 self.toc = "<ul>#{toc_items.join}</ul>".html_safe end end
步骤3:确认强参数配置
确保PostsController中允许body和toc参数:
class PostsController < ApplicationController # ...其他方法 private def post_params params.require(:post).permit(:title, :body, :toc) end end
关键说明
- 直接操作
body.content:has_rich_text :body生成的body是ActionText::RichText对象,content属性存储原始HTML内容,修改它不会触发额外的解析过滤 - 唯一id生成:通过添加索引后缀避免重复标题导致的锚点冲突问题
- 配置生效:修改initializer后必须重启服务器,否则ActionText的过滤器不会更新
内容的提问来源于stack exchange,提问作者Developer3027
相关产品推荐
相关产品推荐

