index is getting called instead of show

2k Views Asked by At

I'm trying to write an API using Ruby on Rails. In my controller class index method is getting called instead of show. Although I am passing parameters.

tried these urls

http://localhost:3000/api/v1/quatertodate/?invoiceStatus=PENDING
http://localhost:3000/api/v1/quatertodate/PENDING
http://localhost:3000/api/v1/quatertodate/:PENDING

In all of the above mentioned cases my index method is getting called instead of show.

Respective Controller class

module Api
module V1
    class QuatertodateController < ApplicationController

        def index   
            invoices = Invoice.select("*").where("invoiceDate >= ?", @@present_date-90)
            render json: {status: 'SUCCESS', messasge: 'LOADED QUATERLY INVOICES', data: invoices}, status: :ok
        end

        def show
            invoices1 = Invoice.select("*").where("invoiceStatus== ? AND invoiceDate >= ?", params[:invoiceStatus], @@present_date-90)
            #invoices1 = Invoice.find(params[:invoiceStatus])
      #invoices1=Invoice.select("*").where("invoiceStatus= ? and invoiceDate >= ?", params[:invoiceStatus], @@present_date-180)
            render json: {status: 'SUCCESS', messasge: 'LOADED QUATERLY INVOICES', data: invoices1}, status: :ok
        end

    end
end

end

NOTE: The commented portion #invoices1 doesn't work either. Throws:

<ActiveRecord::RecordNotFound: Couldn't find Invoice with 'customerId'=>

Schema

create_table "invoices", primary_key: "customerId", id: :integer, default: nil, force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1" do |t|
t.string "customerNumber", limit: 12
t.string "customerType", limit: 5
t.string "invoiceType", limit: 5
t.decimal "invoiceAmt", precision: 65, scale: 30
t.string "invoiceStatus", limit: 12
t.datetime "invoiceDate"

Possible invoiceStatus values: BILLED or PENDING

routes

Rails.application.routes.draw do
namespace 'api' do
    namespace 'v1' do
        resources :invoices
        resources :monthtodate
        resources :quatertodate
        resources :yeartodate
    end
end
end

rake routes route

My objective: To return invoices from last 90 days whose invoice status is PENDING.
I also have tried update method for PATCH request, instead of show but it is throwing this error

AbstractController::ActionNotFound: The action 'update' could not be found for Api:

Removing index method gives following error:

ActiveRecord::RecordNotFound: Couldn't find Invoice with 'customerId'=>"

What am I missing? Can anyone direct me towards right direction? I couldn't find any related docs either.

I'm new to Ruby on Rails.

2

There are 2 best solutions below

2
m. simon borg On BEST ANSWER

If you're going to follow proper Rails and REST conventions you wouldn't use the show action for this. show is for showing one record, and is called with a URL of this format api/v1/quartertodate/:id, where :id is a dynamic variable for the id of the record you want to show. In the controller it is available as params[:id].

index is for showing many records, even if it's not all of the records.

You can handle this with an if...else branch in the index action.

def index   
  @invoices = if params[:invoiceStatus].present?
    Invoice.where("invoiceStatus = ? AND invoiceDate >= ?", params[:invoiceStatus], ninety_days_past)
  else
    Invoice.where("invoiceDate >= ?", ninety_days_past)
  end

  render json: {status: 'SUCCESS', messasge: 'LOADED QUATERLY INVOICES', data: @invoices}, status: :ok
end

def show
  @invoice = Invoice.find(params[:id])
  render json: {status: 'SUCCESS', messasge: 'LOADED INVOICE', data: @invoice}, status: :ok
end

private

def ninety_days_past
  Date.today - 90
end

Notes: You don't need select('*'), and you should be using an instance variable for @invoices because it will require less refactoring if you ever switch to a templating engine for your JSON API. Also, you don't need a global variable for today's date, just use the built in Date library and do Date.today. To find the date 90 days ago you can create a private method ninety_days_past so you're not duplicating the code. If you want this method in every controller just define that method directly in your ApplicationController instead of your QuatertodateController.

5
Evan On

This url will reuest the index action:

 http://localhost:3000/api/v1/quatertodate?invoiceStatus=PENDING

Route next identifies the string ?invoiceStatus=PENDING as id parameter. So it will request the show action.

http://localhost:3000/api/v1/quatertodate/?invoiceStatus=PENDING