You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails多态模型Note的POST创建测试失败,求解决方案

多态模型Note的创建测试用例无法增加计数,如何编写正确的测试?

我有一个多态模型Note,开发环境中功能运行正常,但编写的创建测试用例无法让Note计数增加(路径与参数均正确),请问怎么写正确的测试用例验证创建动作?


相关代码

Note模型

class Note < ApplicationRecord
    belongs_to :commentor, class_name: "User"
    belongs_to :notable, polymorphic: true, touch: true
    belongs_to :program
    belongs_to :organization

    validates :commentor, presence: true, uniqueness: { scope: [:notable_id, :notable_type], message: "can only create one note. Please edit your existing note" }
    validates :content, presence: true, length: { maximum: 150, message: "only 150 characters" }
    validates :program, presence: true
    validates :organization, presence: true
end

控制器

app/controllers/tools/workouts/notes_controller.rb

class Tools::Workouts::NotesController < Tools::NotesController
    before_action :set_routine

    private

    def set_routine
        @notable = current_program.workouts.find(params[:workout_id])
    end
end

app/controllers/tools/notes_controller.rb

def create
    @note = @notable.notes.new(note_params)
    @note.commentor = current_user
    @note.organization = current_organization
    @note.program = current_program
    respond_to do |format|
        if @notable.save
            flash[:success] = t(".success")
            format.html { recede_or_redirect_to [:tools, :program, @notable, program_id: current_program] }
            format.json { render :show, status: :created }
            format.turbo_stream { flash.now[:success] = t(".success") }
        else
            flash[:warning] = t(".error")
            format.html { render :new, status: :unprocessable_entity }
            format.json { render json: @notable.errors, status: :unprocessable_entity }
            format.turbo_stream { flash.now[:warning] = t(".error") }
        end
    end
end

路由

namespace :tools do
  resources :programs, only: %i[] do
    resources :notes
    resources :workouts do
      resources :notes, module: :workouts, except: %i[update destroy edit index]
    end
  end
end

现有测试用例

test "should create note" do
    assert_difference("Note.count") do
        post polymorphic_url([:tools, current_program, @workout, notes]), params: { 
            note: {
                content: "Test workout note"
            }
        }
        puts request.POST.inspect
        puts polymorphic_url([:tools, current_program, @workout, notes])
    end
  
    assert_equal @workout.notes.last.content, "Test workout note"
    assert_equal @workout.notes.last.program, @program
    assert_equal @workout.notes.last.commentor, @user
    assert_equal @workout.notes.last.organization, @organization
    assert_equal @workout.notes.last.notable_type, "Workout"
end

测试结果显示Note计数未增加,保持不变。


问题分析与解决方案

核心问题:控制器创建逻辑错误

你的tools/notes_controller.rb的create方法中,创建@note并赋值关联字段后,错误调用了@notable.save而非@note.save。@notable是Workout对象,保存它不会生成新的Note记录,这直接导致测试中计数无变化。

修正控制器代码

将保存对象改为@note,同时调整错误处理的错误对象:

def create
    @note = @notable.notes.new(note_params)
    @note.commentor = current_user
    @note.organization = current_organization
    @note.program = current_program
    respond_to do |format|
        if @note.save
            flash[:success] = t(".success")
            format.html { recede_or_redirect_to [:tools, :program, @notable, program_id: current_program] }
            format.json { render :show, status: :created, location: @note }
            format.turbo_stream { flash.now[:success] = t(".success") }
        else
            flash[:warning] = t(".error")
            format.html { render :new, status: :unprocessable_entity }
            format.json { render json: @note.errors, status: :unprocessable_entity }
            format.turbo_stream { flash.now[:warning] = t(".error") }
        end
    end
end

调整测试用例

使用明确的路由辅助方法,添加响应状态验证,并重新加载关联对象获取最新数据:

test "should create note" do
    assert_difference("Note.count", 1) do
        post tools_program_workout_notes_path(current_program, @workout), params: { 
            note: {
                content: "Test workout note"
            }
        }
    end

    # 验证请求成功响应
    assert_response :redirect

    # 重新加载workout以获取最新关联的note
    @workout.reload
    created_note = @workout.notes.last

    assert_equal created_note.content, "Test workout note"
    assert_equal created_note.program, current_program
    assert_equal created_note.commentor, current_user
    assert_equal created_note.organization, current_organization
    assert_equal created_note.notable_type, "Workout"
end

额外注意事项

  • 用tools_program_workout_notes_path替代polymorphic_url,更直观且避免路由解析错误
  • 调用@workout.reload确保从数据库获取最新的关联记录
  • 验证响应状态码,确认请求执行成功

内容的提问来源于stack exchange,提问作者Chrismisballs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 14:17:47