ruby-on-railsjsonapi-designjbuilder

How to generate a custom json response with Jbuilder & Rails


In my Ruby on Rails app, bike rental companies can manage all their bikes (reservations, payments etc.).

Context I would like to offer a bike rental companies (shops) the option to implement a booking form on their own website, so they can let customers make a reservation for a bike.

Question In order to manage this, I would like to generate an API controller action showing the availability for a certain bike_category displaying the count for the number of available bikes belonging to this bike_category.

According to this post

Design RESTful query API with a long list of query parameters

I should be able to deal with queries in my api, but how do I return the count in the view using Jbuilder ?

Code

models

class Shop < ApplicationRecord
  has_many :bike_categories, dependent: :destroy
  has_many :bikes, through: :bike_categories
  has_many :reservations, dependent: :destroy
end

class Reservation < ApplicationRecord
  belongs_to :shop
  belongs_to :bike
end

class Bike < ApplicationRecord
  belongs_to :bike_category
  has_many :reservations, dependent: :destroy
end

class BikeCategory < ApplicationRecord
  belongs_to :shop
  has_many :bikes, dependent: :destroy
end

routes

  namespace :api, defaults: { format: :json } do
    namespace :v1 do
      resources :shops, only: [ :show ]
      resources :reservations, only: [ :show, :create ]
      resources :reservation_contacts, only: [:show, :create]
      resources :reservation_options, only: [:show, :create]
      resources :bike_categories, only: [:index, :show] do
        get :availability, on: :member
      end
    end
  end

controllers/api/v1/bike_categories_controller.rb

class Api::V1::BikeCategoriesController < Api::V1::BaseController
  acts_as_token_authentication_handler_for User, only: [:show, :index, :availability]

  def availability
    @user = current_user
    bike_category = params[:bike_category]
    if @user.shop.bike_categories.include? bike_category
      arrival = params[:arrival]
      departure = params[:departure]
      shop = bike_category.shop
      reservations_overlap = shop.reservations.where("reservations.arrival >= ? AND ? >= reservations.arrival", arrival, departure)
      .or(shop.reservations.where("reservations.arrival <= ? AND ? <= reservations.departure", arrival, arrival)).distinct
      unavailable_bikes = []
      reservations_overlap.each do |res|
        if !unavailable_bikes.include? res.bike && res.bike.bike_category == bike_category
          unavailable_bikes << res.bike
        end
      end
      bikes = bike_category.bikes
      @count = (bikes - unavailable_bikes).length
    else
      error
    end
  end

end

views/api/v1/bike_categories.json.jbuilder

# How to return @count?

Solution

  • your code here...
    if @user.shop.bike_categories.include? bike_category
          arrival = params[:arrival]
          departure = params[:departure]
          shop = bike_category.shop
          reservations_overlap = shop.reservations.where("reservations.arrival >= ? AND ? >= reservations.arrival", arrival, departure)
          .or(shop.reservations.where("reservations.arrival <= ? AND ? <= reservations.departure", arrival, arrival)).distinct
          unavailable_bikes = []
          reservations_overlap.each do |res|
            if !unavailable_bikes.include? res.bike && res.bike.bike_category == bike_category
              unavailable_bikes << res.bike
            end
          end
          bikes = bike_category.bikes
          @count = (bikes - unavailable_bikes).length
          render json: @count, status: :ok, adapter: :json
        else
          error = ...some code here...
          render json: error, status: unprocessed_entity, adapter: :json
        end
    

    I would do something like this