2010-12-16 2 views
2

Я использую рубин 1.8.7 и рельсы 3.0.3, проходящие через Dev книги 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) будут делать то же самое.

Спасибо!

ответ

3

Вы вызываете referenced_by_line_item перед тем, как что-либо сделать. Если есть позиции, он возвращает false, поэтому вы не удаляете позиции. Я не думаю, что это то, что вы хотите. Если вы изменили его:

if [email protected]_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 

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

+0

спасибо, что нашли время, чтобы объяснить! Моя главная цель здесь - узнать, что RoR не обладает высоким первичным кодом :) – 2010-12-16 17:36:52

3

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

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

+0

спасибо за указатель! – 2010-12-16 17:36:23

Смежные вопросы