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
.
bike_categories
of which bikes
are available for a given arrival
and departure
date. 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?
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