0

I have a resource called "parameters" that is nested under "tests" in my API. There relation is as follows: "A test has many parameters". I've structured my routes as follows

tests/:test_id/parameters/:parameter_id

and my rake routes gives:

      test_parameters GET    /tests/:test_id/parameters(.:format)                parameters#index {:format=>:json}
                      POST   /tests/:test_id/parameters(.:format)                parameters#create {:format=>:json}
   new_test_parameter GET    /tests/:test_id/parameters/new(.:format)            parameters#new {:format=>:json}
  edit_test_parameter GET    /tests/:test_id/parameters/:id/edit(.:format)       parameters#edit {:format=>:json}
       test_parameter GET    /tests/:test_id/parameters/:id(.:format)            parameters#show {:format=>:json}
                      PATCH  /tests/:test_id/parameters/:id(.:format)            parameters#update {:format=>:json}
                      PUT    /tests/:test_id/parameters/:id(.:format)            parameters#update {:format=>:json}
                      DELETE /tests/:test_id/parameters/:id(.:format)            parameters#destroy {:format=>:json}

I'm writing simple tests to test all the typical actions of my API. Right now, my POST/CREATE is giving me a very puzzling error.

Failures:

  1) ParametersController POST create a new parameter with valid attributes successfully with name and times
     Failure/Error: post :create, :test_id => @test.id, parameter: parameter.attributes, format: :json
     NoMethodError:
       undefined method `parameter_url' for #<ParametersController:0x000001072b4280>
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_dispatch/routing/polymorphic_routes.rb:220:in `polymorphic_method'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_dispatch/routing/polymorphic_routes.rb:114:in `polymorphic_url'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_dispatch/routing/url_for.rb:163:in `url_for'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_controller/metal/rendering.rb:95:in `_process_options'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_controller/metal/streaming.rb:200:in `_process_options'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_controller/metal/renderers.rb:43:in `block in _render_to_body_with_renderer'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_controller/metal/renderers.rb:41:in `_render_to_body_with_renderer'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_controller/metal/renderers.rb:37:in `render_to_body'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/abstract_controller/rendering.rb:25:in `render'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_controller/metal/rendering.rb:16:in `render'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_controller/metal/instrumentation.rb:44:in `block (2 levels) in render'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/activesupport-4.2.2/lib/active_support/core_ext/benchmark.rb:12:in `block in ms'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/activesupport-4.2.2/lib/active_support/core_ext/benchmark.rb:12:in `ms'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_controller/metal/instrumentation.rb:44:in `block in render'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_controller/metal/instrumentation.rb:87:in `cleanup_view_runtime'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/activerecord-4.2.2/lib/active_record/railties/controller_runtime.rb:25:in `cleanup_view_runtime'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_controller/metal/instrumentation.rb:43:in `render'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/responders-2.1.0/lib/action_controller/responder.rb:258:in `display'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/responders-2.1.0/lib/action_controller/responder.rb:214:in `api_behavior'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/responders-2.1.0/lib/action_controller/responder.rb:191:in `rescue in to_format'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/responders-2.1.0/lib/action_controller/responder.rb:185:in `to_format'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/responders-2.1.0/lib/action_controller/responder.rb:163:in `respond'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/responders-2.1.0/lib/action_controller/responder.rb:156:in `call'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/responders-2.1.0/lib/action_controller/respond_with.rb:203:in `respond_with'
     # ./app/controllers/parameters_controller.rb:13:in `create'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_controller/metal/implicit_render.rb:4:in `send_action'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/abstract_controller/base.rb:198:in `process_action'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_controller/metal/rendering.rb:10:in `process_action'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/abstract_controller/callbacks.rb:20:in `block in process_action'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/activesupport-4.2.2/lib/active_support/callbacks.rb:117:in `call'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/activesupport-4.2.2/lib/active_support/callbacks.rb:117:in `call'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/activesupport-4.2.2/lib/active_support/callbacks.rb:555:in `block (2 levels) in compile'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/activesupport-4.2.2/lib/active_support/callbacks.rb:505:in `call'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/activesupport-4.2.2/lib/active_support/callbacks.rb:505:in `call'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/activesupport-4.2.2/lib/active_support/callbacks.rb:92:in `_run_callbacks'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/activesupport-4.2.2/lib/active_support/callbacks.rb:776:in `_run_process_action_callbacks'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/activesupport-4.2.2/lib/active_support/callbacks.rb:81:in `run_callbacks'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/abstract_controller/callbacks.rb:19:in `process_action'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_controller/metal/rescue.rb:29:in `process_action'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_controller/metal/instrumentation.rb:32:in `block in process_action'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/activesupport-4.2.2/lib/active_support/notifications.rb:164:in `block in instrument'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/activesupport-4.2.2/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/activesupport-4.2.2/lib/active_support/notifications.rb:164:in `instrument'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_controller/metal/instrumentation.rb:30:in `process_action'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/activerecord-4.2.2/lib/active_record/railties/controller_runtime.rb:18:in `process_action'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/abstract_controller/base.rb:137:in `process'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionview-4.2.2/lib/action_view/rendering.rb:30:in `process'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_controller/test_case.rb:632:in `process'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_controller/test_case.rb:65:in `process'
     # /Users/naseem.alnaji/.rvm/gems/ruby-2.1.1/gems/actionpack-4.2.2/lib/action_controller/test_case.rb:514:in `post'
     # ./spec/controllers/parameters_controller_spec.rb:34:in `block (5 levels) in <top (required)>'
     # ./spec/controllers/parameters_controller_spec.rb:33:in `block (4 levels) in <top (required)>'

I've tried changing the formats in how I'm submitting the POST but that hadn't changed anything. For now, my rspec test looks like this:

    "spec/controllers/parameters_controller_spec.rb"
    require 'spec_helper'
    describe ParametersController do
      before :each do
        @test = FactoryGirl.create(:test, id: 1, name: 'Eccentric Tech')
        @test.save
      end

      # ...

      describe 'POST create a new parameter' do
        context 'with valid attributes' do
          it 'successfully with name and times' do
            parameter = FactoryGirl.build(:parameter)
            expect {
              post :create, :test_id => @test.id, parameter: parameter.attributes, format: :json
            }.to change(Parameter, :count).by(1)
          end
        end
        context 'with invalid attributes' do
          it 'fails without a name' do
            parameter = FactoryGirl.build(:no_name_parameter)
            expect {
              post :create, :test_id => @test.id, parameter: parameter.attributes, format: :json
            }.to change(Parameter, :count).by(0)
          end
          it 'fails without belonging to a test' do
            parameter = FactoryGirl.build(:no_test_parameter)
            expect {
              post :create, :test_id => @test.id, parameter: parameter.attributes, format: :json
            }.to change(Parameter, :count).by(0)
          end
        end
      end

      # ...

    end

My Factory:

"spec/factories/parameters.rb"
require 'faker'

FactoryGirl.define do
  factory :parameter do |f|
    f.name { "#{Faker::Hacker.noun}" }
    f.value { Faker::Number.number(2) }
    f.test_id { 1 }
  end

  factory :no_name_parameter, parent: :parameter do |f|
    f.name nil
    f.value { Faker::Number.number(2) }
    f.test_id { 1 }
  end

  factory :no_test_parameter, parent: :parameter do |f|
    f.name { "#{Faker::Hacker.noun}" }
    f.value { Faker::Number.number(2) }
    f.test_id nil
  end
end

And finally, my controller:

class ParametersController < ApplicationController
  respond_to :json

  def index
    respond_with Parameter.all
  end

  def show
    respond_with Parameter.find(params[:id])
  end

  def create
      respond_with Parameter.create(parameter_params)
  end

  def update
    respond_with Parameter.update(params[:id], parameter_params)
  end

  def destroy
    respond_with Parameter.destroy(params[:id])
  end

  private
    def parameter_params
      params.require(:parameter).permit(:name, :value, :test_id)
    end
end

routes.rb:

Rails.application.routes.draw do
  scope :defaults => { :format => :json } do
    resources :services do
      resources :tests
    end

    resources :tests do
      resources :parameters
      resources :singular_results
      resources :dataset_results
    end
  end
end

1 Answers1

0

I solved this myself but I have nooooo idea why it works. If someone could explain it please do :)

All I did was make this small change to my controller:

def create
  respond_with Parameter.create(parameter_params), location: nil
end

Found a good explanation: Rails: NoMethodError (Undefined method _url for _controller. I can't seem to respond_with json properly after my create. Why?

Community
  • 1
  • 1