Last active
May 12, 2022 09:45
-
-
Save azdrenymeri/276bada517fbd6571398bd4474980bf2 to your computer and use it in GitHub Desktop.
RESTful controller with filterrific integration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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