Понимание ответа_с Rails 3

Использование нового метода ActionController respond_with... как он определяет, что отображать, когда действие (сохранение) выполнено успешно, а когда нет?

Я спрашиваю, потому что я пытаюсь получить спецификацию, сгенерированную скаффолдом (приведенную ниже), чтобы пройти, хотя бы так, чтобы я мог ее понять. Приложение работает нормально, но, как ни странно, оно отображает /carriers (по крайней мере, так говорит URL-адрес браузера), когда проверка не удалась. Тем не менее, спецификация ожидает "new" (и я тоже, если на то пошло), но вместо этого получает <"">. Если я изменю спецификацию, чтобы ожидать "", это все равно не удастся.

Когда он отображает /carriers, эта страница показывает сообщения об ошибках рядом с полями, которые не прошли проверку, как и следовало ожидать.

Кто-нибудь, знакомый с respond_with, может посмотреть, что здесь происходит?

#carrier.rb
  validates :name, :presence => true 

#carriers_controller.rb
class CarriersController < ApplicationController
  respond_to :html, :json

...

  def new
    respond_with(@carrier = Carrier.new)
  end

  def create
     @carrier = Carrier.new(params[:carrier])
     flash[:success] = 'Carrier was successfully created.' if @carrier.save
     respond_with(@carrier) 
  end

Спецификация, которая терпит неудачу:

#carriers_controller_spec.rb
require 'spec_helper'

describe CarriersController do

  def mock_carrier(stubs={})
    (@mock_carrier ||= mock_model(Carrier).as_null_object).tap do |carrier|
      carrier.stub(stubs) unless stubs.empty?
    end
  end


  describe "POST create" do
    describe "with invalid params" do
      it "re-renders the 'new' template" do
        Carrier.stub(:new) { mock_carrier(:save => false) }
        post :create, :carrier => {}
        response.should render_template("new")
      end
    end
  end
end

с этой ошибкой:

  1) CarriersController POST create with invalid params re-renders the 'new' template
     Failure/Error: response.should render_template("new")
     expecting <"new"> but rendering with <"">.
     Expected block to return true value.
     # (eval):2:in `assert_block'
     # ./spec/controllers/carriers_controller_spec.rb:81:in `block (4 levels) in <top (required)>'

person Meltemi    schedule 15.12.2010    source источник
comment
Вы вызываете Carrier.new как в #new, так и в #create действиях вашего контроллера несущей. Я думаю, это должно быть Carrier.create(params[:carrier]) в методе действия def create.   -  person Ernesto    schedule 26.09.2012


Ответы (1)


tl:dr

Добавьте хэш ошибки в макет:

Carrier.stub(:new) { mock_carrier(:save => false, 
                       :errors => { :anything => "any value (even nil)" })}

Это вызовет желаемое поведение в respond_with.

Что здесь происходит

Добавьте это после post :create

response.code.should == "200"

Это не удается с expected: "200", got: "302". Таким образом, он перенаправляет вместо отображения нового шаблона, когда этого не должно быть. Куда это идет? Дайте ему путь, который, как мы знаем, потерпит неудачу:

response.should redirect_to("/")

Теперь он терпит неудачу с Expected response to be a redirect to <http://test.host/> but was a redirect to <http://test.host/carriers/1001>

Предполагается, что спецификация проходит путем рендеринга шаблона new, что является нормальным ходом событий после того, как save на фиктивном объекте Carrier возвращает false. Вместо этого respond_with перенаправляет на show_carrier_path. Что просто неправильно. Но почему?

После некоторого копания в исходном коде кажется, что контроллер пытается отобразить «перевозчики/создать». Такого шаблона нет, поэтому возникает исключение. Спасательный блок определяет, что запрос является POST и в хэше ошибки ничего нет, после чего контроллер перенаправляется на ресурс по умолчанию, которым является макет Carrier.

Это озадачивает, так как контроллер не должен предполагать, что существует действительный экземпляр модели. В конце концов, это create. На данный момент я могу только предположить, что тестовая среда каким-то образом использует ярлыки.

Таким образом, обходным путем является предоставление поддельного хэша ошибки. Обычно что-то будет в хэше после того, как save завершится ошибкой, так что в этом есть смысл.

person zetetic    schedule 15.12.2010
comment
Отлично сделано! Считаете ли вы это ошибкой? Я недостаточно знаю о Rails, чтобы составить мнение. Но ваш ответ помогает мне учиться! Еще раз спасибо... - person Meltemi; 16.12.2010