Active Model Serializer, проверяющий, какой сериализатор используется для рендеринга ответа

Я использую сериализаторы активных моделей для рендеринга ответов JSON от контроллера рельсов.

У меня есть такое действие контроллера:

def show
  @foo = Foo.find(params[:id])
  if @foo.user == current_user
    render json: @foo, serializer: FooSerializer
  else
    render json: @foo, serializer: TrimmedFooSerializer
  end
end

Я хочу иметь возможность проверить, какой сериализатор использовался в моих тестах контроллера Rspec. Можно ли получить ссылку на сериализатор из тестов?

ОБНОВЛЕНИЕ:

Я не думаю, что это правильное использование сериализатора. Теперь у меня есть логика в самом сериализаторе для условного включения атрибутов. Контроллер не должен заботиться о том, какой сериализатор использовать.


person Charlie    schedule 28.02.2014    source источник


Ответы (4)


Вы можете попробовать это. Я предполагаю, что вы используете factory_girl. Вы можете написать другой тест, вернув другого пользователя для current_user

describe "show" do
  it "should use FooSerializer to serialize if the logged in user is the same as params user" do
    user = FactoryGirl.create(:user)
    controller.stub(:current_user).and_return(user)
    FooSerializer.any_instance.should_receive(:to_json).and_return("{\"key\": \"value\"")
    get :show, :id => user.id
    response.should be_success
  end
end
person usha    schedule 28.02.2014

Прошло некоторое время с тех пор, как кто-то ответил, но на случай, если будущие гуглеры найдут это, мне нравится следующий подход:

RSpec::Matchers.define :serialize_object do |object|
  match do |response|
    @serializer_klass.new(object).to_json == response.body
  end

  chain :with do |serializer_klass|
    @serializer_klass = serializer_klass
  end
end

Затем в ваших тестах вы можете сделать:

expect(response).to serialize_object(claim).with(ClaimSerializer)

Обратите внимание, что я не назвал сопоставитель «сериализовать», потому что shoulda уже определяет сопоставитель с таким именем.

person Dan Draper    schedule 20.10.2014
comment
очень элегантный полезный подход - person Calin; 25.04.2015

Чтобы уточнить ответ Дэна Дрейпера, я обнаружил, что при использовании адаптера JsonApi это путь:

RSpec::Matchers.define :serialize_resource do |object|
  match do |response|
    serialized_json(object) == response.body
  end

  chain :with do |serializer_klass|
    @serializer_klass = serializer_klass
  end

  failure_message do |response|
    "expected response body #{serialized_json(object)}, got #{response.body}"
  end

  def serialized_json(object)
    serializer = @serializer_klass.new(object)
    adapted = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
    adapted.serializable_hash.to_json
  end
end
person Knightstick    schedule 15.03.2017

Я взял то, что сделал Knightstick выше, и немного улучшил его, например, сообщение об ошибке и добавив возможность обрабатывать как отдельный ресурс, так и набор ресурсов (я использую гем active_model_serializers, версия 0.10.0).

RSpec::Matchers.define :serialize_resource do |resource|
  match do |response|
    serialized_json(resource) == response.body
  end

  chain :with do |serializer_klass|
    @serializer_klass = serializer_klass
  end

  failure_message do |response|
    "expected response body #{serialized_json(resource).inspect}, got #{response.body.inspect}"
  end

  def serialized_json(resource)
    options = if resource.is_a?(Array)
                { each_serializer: @serializer_klass }
              else
                { serializer: @serializer_klass }
              end

    serializable = ActiveModelSerializers::SerializableResource.new(resource, options)
    serializable.serializable_hash.to_json
  end
end
person leandroico    schedule 15.05.2017