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
相关产品推荐
相关产品推荐

