Skip to content

Instantly share code, notes, and snippets.

@azdrenymeri
Last active May 12, 2022 09:45
Show Gist options
  • Save azdrenymeri/276bada517fbd6571398bd4474980bf2 to your computer and use it in GitHub Desktop.
Save azdrenymeri/276bada517fbd6571398bd4474980bf2 to your computer and use it in GitHub Desktop.
RESTful controller with filterrific integration
module Api
module V1
# This is a module that provides a RESTful action for all API controllers.
# Uses filterrific gem to filter records.
# Uses will_paginate gem for pagination.
module RestfulController
extend ActiveSupport::Concern
included do
before_action :resource_model, only: [:index, :show, :create, :update, :destroy]
before_action :resource_params, only: [:create, :update]
def index
@filterrific = initialize_filterrific(
resource_model,
params[:filterrific],
default_filter_params: filter_default_scopes,
available_filters: filter_scopes
) or return
@resource_records = @filterrific.find.page(page_number).per_page(page_size)
render json: @resource_records, meta: pagination_dict(@resource_records), status: :ok
end
def show
@resource = resource_model.find(params[:id])
if @resource
render json: @resource, status: :ok
else
render json: {resource: @resource, message: "Resource not found", errors: @resource.errors.full_messages}, status: :not_found
end
end
def create
@resource = resource_model.new(resource_params)
if @resource.save
render json: @resource, status: :created
else
render json: {resource: @resource, message: "Resource not created", errors: @resource.errors.full_messages}, status: :unprocessable_entity
end
end
def update
@resource = resource_model.find(params[:id])
if @resource.update(resource_params)
render json: @resource, status: :ok
else
render json: {resource: @resource, message: "Resource not updated", errors: @resource.errors.full_messages}, status: :unprocessable_entity
end
end
def destroy
@resource = resource_model.find(params[:id])
if @resource.destroy
render json: {message: "Resource destroyed"}, status: :ok
else
render json: {resource: @resource, message: "Resource not destroyed", errors: @resource.errors.full_messages}, status: :unprocessable_entity
end
end
end
class NotOverriden < StandardError
def initialize(arg)
super arg.to_s
end
end
# This is a hook method that returns the model class associated with the current controller.
# @raise [NotOverriden] if the method is not overriden.
# @return [Class] the model class associated with the current controller.
def resource_model() = raise(NotOverriden.new("Pass the model class you want to use for this controller"))
# This is a hook method that permits the model params
# @raise [NotOverriden] if the method is not overriden.
# @return [ActionController::Parameters] the permitted paramenters
def resource_params() = raise(NotOverriden.new("You must define the permitted parameter for the current model"))
# This is a hook method that returns an array of symbols with the names of scopes of the current model.
# That we can use to filter the data
# @raise [NotOverriden] if the method is not overriden.
# @return [Array<Symbol>] the names of scopes of the current model.
def filter_scopes() = raise(NotOverriden.new("You must define the scopes that can be used for filtering"))
# This is a hook method that returns an array of symbols with the names of default scopes of the current model.
# That will filter data by default
# @raise [NotOverriden] if the method is not overriden.
# @return [Hash<Symbol>] the names of default scopes of the current model.
def filter_default_scopes() = raise(NotOverriden.new("You must define the default scopes for filtering"))
# Page number for pagination to start
# @return [Integer] the page number for pagination to start
def page_number
page ||= params.dig(:page, :number) || 1
page = 1 if page.to_i == 0
page
end
# Number of items per page
# @return [Integer] the number of items per page
def page_size
per_page ||= params.dig(:page, :size) || 25
per_page
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment