метод уничтожения не работает - PullRequest
2 голосов
/ 16 декабря 2010

Я использую ruby ​​1.8.7 и rails 3.0.3, проходя книгу разработчиков Agile Rails от PragProg

Этот метод уничтожения моего ProductsController не удаляет мой продукт, и я не понимаю, почему.

Вот мой первый крой, который я ожидал «просто сработать»

  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

У меня есть метод 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 ]

3 голосов
/ 16 декабря 2010

Вы звоните 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

Хотя я не вижу смысла проверять позиции, прежде чем принять решение об их удалении, кромедля небольшого увеличения производительности.

3 голосов
/ 16 декабря 2010

delete и destroy имеют существенное различие - удаление просто удаляет строку, без вызова обратных вызовов, как описано в http://www.nickpeters.net/2007/12/21/delete-vs-destroy/

. В этом случае удаление обходит ваш метод before_destroy,который при запуске добавляет ошибки к объекту.Когда вы используете delete, он игнорирует ошибки и, таким образом, меняет счетчик.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...