销毁方法似乎不起作用

时间:2010-12-16 14:46:54

标签: ruby-on-rails ruby-on-rails-3

我正在使用ruby 1.8.7和rails 3.0.3浏览PragProg的Agile Rails开发书

我的ProductsController上的这个destroy方法不会删除我的产品,我不明白为什么。

这是我的第一次切入,我希望“正常工作”

  def destroy
    @product = Product.find(params[:id])
    @product.destroy
    respond_to do |format|
      format.html { redirect_to(products_url) }
      format.xml  { head :ok }
    end
  end

但我断言Product.count的测试失败了。

如果我改为使用这样的删除类方法:

  def destroy
    Product.delete(params[:id])
    respond_to do |format|
      format.html { redirect_to(products_url) }
      format.xml  { head :ok }
    end
  end

我的测试通过了。

这是测试

  test "should destroy product" do
    assert_difference('Product.count', -1) do
      if @product.referenced_by_line_item
        @product.line_items.remove_all
      end
      delete :destroy, :id => @product.to_param
    end

    assert_redirected_to products_path
  end

我的Product model类上有一个before_destroy方法

  def referenced_by_line_item
    if line_items.count.zero?
      return true
    else
      errors.add(:base, 'Line Items present')
      return false
    end
  end

任何想法我在这里做错了什么?通过阅读文档(以及在此处搜索其他问题),我希望@ product.destroy和Product.delete(id)能够做同样的事情。

谢谢!

2 个答案:

答案 0 :(得分:3)

deletedestroy有一个主要区别 - 删除只是删除行,而不调用回调,如http://www.nickpeters.net/2007/12/21/delete-vs-destroy/

中所述

在这种情况下,使用delete会绕过您的before_destroy方法,该方法在运行时会向对象添加错误。使用delete时,它会忽略错误,从而更改计数。

答案 1 :(得分:3)

在执行任何操作之前,您正在调用referenced_by_line_item。如果有订单项,则返回false,因此您不会删除订单项。我不认为这是你想要的行为。如果您将其更改为:

  if !@product.referenced_by_line_item
    @product.line_items.remove_all
  end
  delete :destroy, :id => @product.to_param

然后@product.destroy可能会有用。

尽管在referenced_by_line_item中反转逻辑可能更有意义。更有意义的是,如果有与此产品关联的订单项,则此订单会引用此产品。我认为你的逻辑是倒退的。

此外,布尔方法应以'?'

结尾

我看到了这里的复杂情况。如果有行项目,您希望它返回false,以便它不保存,但返回值与方法名称不一致。也许这样的事情会更好:

def no_line_items_present?
  if line_items.count > 0
    # add errors
    return false
  else
    return true
  end
end

然后你可以说:

  @product.line_items.remove_all unless @product.no_line_items_present?
  delete :destroy, :id => @product.to_param

虽然在决定删除订单项之前我没有看到检查订单项的重点,除了性能略有提升。