我的控制器中有一个删除功能,如下所示:
before_action :set_form, only: [:show, :edit, :update, :destroy]
def destroy
if @form.destroy
render json: @form, status: :ok
else
render json: @form.errors, status: :not_found
end
end
private
def set_form
@form = Form.find(params[:id])
end
end
我有两个问题:
1)我没有正确执行删除时返回404。这是合理的状态代码吗?我查看了所有4XX状态代码,这是最有意义的。
2)我不确定我将如何为render json: @form.errors, status: :not_found
编写测试。
以下是我的尝试:
context "Cannot delete the model" do
it "responds successfully with an HTTP 404 status code" do
delete :destroy, id: 100000
expect(response).to have_http_status(404)
end
end
问题是我收到错误消息ActiveRecord::RecordNotFound:Couldn't find Visa with 'id'=10000
而不是delete
操作实际失败。如何模拟delete
操作失败?
答案 0 :(得分:1)
该错误与您在开发甚至生产中获得的错误相同。这条线...
@form = Form.find(params[:id])
如果未找到包含已发送ID的Form
记录,则会引发异常。
如果找不到@form
并且您找到了继续的机制,@form.destroy
仍然无效,因为destroy
个对象上没有方法nil
,并且errors
个对象上也没有方法nil
。
如果您坚持按照描述处理破坏方法,则需要执行类似......
的操作before_action :set_form, only: [:show, :edit, :update] #remove destroy
def destroy
@form = Form.find_by(id: params[:id])
if @form
@form.destroy
render json: @form, status: :ok
else
render json: 'record not found for delete', status: :not_found
end
end
答案 1 :(得分:0)
您的set_form
方法会引发该错误,您必须将其捕获或使用find_by_id
中的destroy
。
def set_form
@form = Form.find(params[:id])
rescue ActiveRecord::RecordNotFound
end
这种方式@form
将nil
if
。
对于HTTP状态代码,您可以考虑使用422。
答案 2 :(得分:0)
当您在ID无效的记录上调用ActiveRecord::RecordNotFound
时,Rails会引发.find
。这是一个非常理想的行为,因为它为无法找到资源提供了一个很好的捕获。
默认设置是发送404 - 未找到的标头。对于HTML请求类型,它还会发送默认错误页面。
相反,问题在于你如何测试它。
如果要测试rails会引发错误:
context "Cannot delete the model" do
it "raises an error when the id is not valid" do
bypass_rescue
expect { delete :destroy, id: 100000 }.to raise_error(ActiveRecord::RecordNotFound)
expect(response).to have_http_status(404)
end
end
但是,如果您想测试删除模型因任何其他原因(记录被锁定或用户未获得授权)失败,您应该在数据库中使用灯具或工厂设置记录并提供有效的ID - 您还应该提供正确的响应代码(422或401)。
至于模拟删除失败,您可以使用allow_any_instance_of(SomeModel).to receive(:destroy).and_return(false)
。