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

Rspec Rails控制器测试无法传递图片参数问题排查

问题:Post控制器Create动作触发图片不能为空验证错误

我正在测试Post控制器的create动作,其余控制器的create动作均正常运行。经调试发现问题出在参数传递上:从Post工厂传递的图片在控制器中为空,导致创建Post时触发Images cannot be blank验证错误。

相关代码

post_spec.rb

describe 'POST #create' do
    it 'check post creation' do
      new_post = build :post, user: user
      attrs = new_post.attributes
      attrs.store(:images, [ Rack::Test::UploadedFile.new(image_url, 'image/jpg') ])
      post posts_path, params: { post: new_post.attributes }
      expect(response).to be_success
    end
end

post.rb(模型)

class Post < ApplicationRecord
  belongs_to :user

  has_many :comments, dependent: :destroy
  has_many :likes, dependent: :destroy
  has_many_attached :images

  validates :user_id, presence: true
  validates :title, presence: true, length: { minimum: 1, maximum: 1000 }
  validates :images, presence: true, limit: { min: 1, max: 10 },
                     content_type: ['image/jpg', 'image/jpeg', 'image/png', 'image/webp']
end

post.rb(FactoryBot工厂)

image_url = '/home/dev/Downloads/a1.jpg'

FactoryBot.define do
  factory :post do
    title { Faker::Lorem.sentence }
    images { Rack::Test::UploadedFile.new(image_url, 'image/jpg') }
    user
  end
end

post_controller.rb

def create
    @post = Post.new(post_params)
    if @post.save
      redirect_to post_url(@post), notice: 'Post was successfully created.'
    else
      render :new, status: :unprocessable_entity
    end
end

def post_params
    params.require(:post).permit(:title, :user_id, images: [])
end

调试信息

  • 检查@post错误输出:['Images cannot be blank']
  • post_spec中的new_post实例:#<Post id: nil, title: "Sequi excepturi quam quos.", user_id: 307, created_at: nil, updated_at: nil>
  • post_spec中的new_post.attributes内容:{"id"=>nil, "title"=>"Sequi excepturi quam quos.", "user_id"=>307, "created_at"=>nil, "updated_at"=>nil}

问题分析

  1. new_post.attributes仅包含模型的数据库字段,不会包含Active Storage的附件(images),因为附件不属于模型的核心数据库属性。
  2. 你在代码中给attrs添加了images参数,但最终发起请求时用的是new_post.attributes,导致添加的图片参数根本没传到控制器。
  3. 工厂中定义的images是单个Rack::Test::UploadedFile实例,但模型用的是has_many_attached,需要传入数组格式的图片参数。

解决办法

方法一:修正spec中的参数传递

直接使用添加了图片的attrs发起请求,同时移除attributes里不需要的字段(如id、created_at):

describe 'POST #create' do
    it 'check post creation' do
      new_post = build :post, user: user
      attrs = new_post.attributes.except('id', 'created_at', 'updated_at')
      attrs[:images] = [ Rack::Test::UploadedFile.new('/home/dev/Downloads/a1.jpg', 'image/jpg') ]
      post posts_path, params: { post: attrs }
      expect(response).to be_success
    end
end

方法二:使用attributes_for构建参数(更简洁)

直接用FactoryBot的attributes_for方法生成参数,再合并图片:

describe 'POST #create' do
    it 'check post creation' do
      post_attrs = attributes_for(:post).merge(
        images: [ Rack::Test::UploadedFile.new('/home/dev/Downloads/a1.jpg', 'image/jpg') ]
      )
      post posts_path, params: { post: post_attrs }
      expect(response).to be_success
    end
end

方法三:修改工厂适配多附件格式

把工厂中的images改成数组格式,这样使用attributes_for时无需额外处理:

image_url = '/home/dev/Downloads/a1.jpg'

FactoryBot.define do
  factory :post do
    title { Faker::Lorem.sentence }
    images { [Rack::Test::UploadedFile.new(image_url, 'image/jpg')] }
    user
  end
end

对应的spec可以简化为:

describe 'POST #create' do
    it 'check post creation' do
      post posts_path, params: { post: attributes_for(:post) }
      expect(response).to be_success
    end
end

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 16:54:26