2

I have an API-only Rails 5 app.

My customers_controller_test fails with

ActionView::MissingTemplate: Missing template api/v1/customers/show, application/show with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :jbuilder]

I can't understand why.

The controller looks like this (Scaffold)

  # POST /customers
  # POST /customers.json
  def create
    @customer = Customer.new(customer_params)

    if @customer.save
      render :show, status: :created, location: api_v1_customer_url(@customer)
    else
      render json: @customer.errors, status: :unprocessable_entity
    end
  end

  # PATCH/PUT /customers/1
  # PATCH/PUT /customers/1.json
  def update
    if @customer.update(customer_params)
      render :show, status: :ok, location: api_v1_customer_url(@customer)
    else
      render json: @customer.errors, status: :unprocessable_entity
    end
  end

So why does POST return HTML when PUT correctly returns JSON?

The test passes fine with this change:

  # POST /customers
  # POST /customers.json
  def create
    @customer = Customer.new(customer_params)

    if @customer.save
      render json: 'show', status: :created, location: api_v1_customer_url(@customer)
    else
      render json: @customer.errors, status: :unprocessable_entity
    end
  end

Is anyone able to explain that?

ringe
  • 812
  • 6
  • 14
  • This comment on how to set default format solved my issue: http://stackoverflow.com/a/6519357/1062276 – ringe Dec 19 '16 at 08:08

2 Answers2

4

The cause of the error is on this line:

render :show, status: :created, location: api_v1_customer_url(@customer)

calling render(:show) will tell rails to look for the "show" template and render it. Rails is looking for that template and can't find it, so it raises an error.

Antarr's answer provides a good solution. For your situation I would simplify it to the following, since I doubt you're supporting more than one response format for your API.

def create
  customer = Customer.new(customer_params)
  if customer.save
    render json: customer, status: :created
  else
    render json: customer.errors, status: :unprocessable_entity
  end
end

Note I also took out the location parameter because I'm not sure what it's supposed to do

Michael Hewson
  • 1,444
  • 13
  • 21
  • The "show" template is a jbuilder one. But why does it not fail on update? – ringe Dec 19 '16 at 07:57
  • hmm... if there *is* a show.json.jbuilder template, and it's not being found, then I guess the default format is html and rails is looking for an html template. Which explains why setting the default format to json solved your problem, to reference your comment above – Michael Hewson Dec 20 '16 at 03:42
0

Your code is trying to render a template

def create
  customer = Customer.new(customer_params)
  respond_to do |format|
    format.json do
      if customer.save
        render json: customer, status: :created, , location: api_v1_customer_url(@customer
      else
        render json: customer.errors, status: :unprocessable_entity
      end
    end
  end
end
Antarr Byrd
  • 24,863
  • 33
  • 100
  • 188