Search code examples
ruby-on-railsjsonresthas-manybelongs-to

Rails JSON Rest API: Getting Child Class from Parent via API Call


I have two API controllers in my Rails app for a RESTful setup:

  • StoresController (has many products)
  • ProductsController (has one store)

How can I write the API so that

http://localhost:3000/api/v1/stores/37/products

returns only the products for that store(in this case store #37)? I think I'm missing a route and controller method to make that happen.

Routes

    namespace :api, defaults: {format: 'json'} do
      namespace :v1 do
        resources :stores
        resources :licenses
      end
    end

API Controllers

APIController:

    module Api
      module V1
        class ApiController < ApplicationController
          respond_to :json
          before_filter :restrict_access

          private

          def restrict_access
            api_app = ApiApp.find_by_access_token(params[:access_token])
            head :unauthorized unless api_app
          end
        end
      end
    end

StoresController:

  module Api
    module V1
      class StoresController < ApiController

        def index
          respond_with Store.all
        end

        def show
          respond_with Store.find_by_id(params[:id])
        end
      end
    end
  end

ProductsController:

    module Api
      module V1
        class ProductsController < ApiController
          def index
            respond_with Product.all
          end

          def show
            respond_with Product.find_by_id(params[:id])
          end
        end
      end
    end

Thanks for any insight.


Solution

  • You want nested resources in your routes:

    resources :stores do
      resources :products
    end
    

    So you have those routes:

    GET        /stores/:id
    GET/POST   /stores/:store_id/products
    PUT/DELETE /stores/:store_id/products/:id
    

    You'll may also want shallow routes, to avoid deeply nested resources:

    resources :stores, shallow:true do
      resources :products
    end
    

    So you have those routes:

    GET        /stores/:id
    GET/POST   /stores/:store_id/products
    PUT/DELETE /products/:id
    

    Once you have the routes, you may just first load the parent store, and use the products association:

    @store = Store.find(params[:store_id])
    @products = store.products