Rails 7 + Ransack搜索Action Text富文本字段报错求助
Rails 7 + Ransack 4: 解决Action Text字段搜索报错
undefined method 'type' for nil:NilClass 问题根源
body并非Post表的直接字段,而是通过has_rich_text :body自动创建的rich_text_body关联,存储在action_text_rich_texts表中。直接将body加入ransackable_attributes会导致Ransack尝试在Post模型中查找不存在的字段,触发nil:NilClass错误。ransackable_associations配置错误:has_rich_text创建的关联名称是rich_text_body,而非action_text_rich_texts,错误的关联名称会让Ransack无法识别关联表。
解决方案步骤
- 修正Post模型的Ransack配置,移除错误的属性声明,替换正确的关联名称,并添加自定义ransacker映射关联字段。
- 调整控制器查询逻辑,确保关联表被正确连接,避免查询异常。
修改后的代码
Post模型
class Post < ApplicationRecord has_rich_text :body has_many :comments, dependent: :destroy belongs_to :user has_one_attached :post_image validates :title, presence: { message: 'must be given please' }, length: { minimum: 5 } validates :body, presence: true, length: { minimum: 10 } validate :post_body_length validate :acceptable_image # 自定义ransacker,将body搜索映射到关联表的body字段 ransacker :body, type: :string do ActionText::RichText.arel_table[:body] end def self.ransackable_attributes(_auth_object = nil) # 移除body,它不是Post的直接属性 %w[title created_at updated_at user_id] end def self.ransackable_associations(_auth_object = nil) # 使用正确的关联名称rich_text_body %w[users comments rich_text_body] end private def acceptable_image return unless post_image.attached? errors.add(:post_image, 'is too big') unless post_image.blob.byte_size <= 5.megabyte acceptable_types = ['image/jpeg', 'image/png'] return if acceptable_types.include?(post_image.content_type) errors.add(:post_image, 'must be a JPEG or PNG') end def post_body_cant_be_empty if self.body.blank? self.errors.add(:body, "can't be empty") end end def post_body_length if self.body.to_plain_text.length < 10 self.errors.add(:body, 'is too short (minimum is 10 characters)') end end end
SearchesController
class SearchesController < ApplicationController def index @query = Post.ransack(params[:q]) # joins确保关联表被连接,includes预加载优化性能 @posts = @query.result.joins(:rich_text_body).includes(:rich_text_body, :user) end end
搜索表单(无需修改)
<%= search_form_for @query, url: searches_path, method: :get, html: { class: "d-flex", role: "search" } do |f| %> <%= f.search_field :title_or_body_cont, class: "form-control me-2", placeholder: "Search title or body..." %> <%= f.submit "Search", class: "btn btn-outline-secondary-light btn-sm" %> <% end %>
说明
- 自定义ransacker让Ransack识别
body搜索条件,自动映射到action_text_rich_texts.body字段,原表单的title_or_body_cont参数可直接生效。 joins(:rich_text_body)强制连接关联表,确保Ransack能访问到关联字段;includes用于预加载关联数据,避免N+1查询问题。
内容的提问来源于stack exchange,提问作者Yurii
相关产品推荐
相关产品推荐

