Move you actions logic to services and keep controllers clean
Add to your Gemfile:
gem "api_service_c8r", github: "datacrafts-io/api_service_c8r"
Include ApiServiceC8r::Base
module to application_controller.rb
class ApplicationController < ActionController::API
include ApiServiceC8r::Base
def current_user; end
end
Create you posts_controller.rb
class Api::V1::PostsController < ApplicationController
target_model Post
use_policy on: %i[index create destroy], policy_scope: %i[index destroy]
use_pagination on: %i[index]
use_serializer PostsSerializer, on: %i[index]
action :index
action :create, render_result: false, without_initial_scope: true
action :destroy, render_result: false
end
By default using Blueprinter
serializer
class PostsSerializer < Blueprinter::Base
identifier :id
fields :title, :body
end
By default using Pundit
policy
class PostPolicy < ApplicationPolicy
def index?
true
end
alias create? index?
alias destroy? index?
class Scope
attr_reader :user, :scope
def initialize(user, scope)
@user = user
@scope = scope
end
def resolve
user.posts
end
end
end
By default using Kaminari
pagination
After that you need to create services for each action and implement call
method in them:
- For
index
action inservices/api/v1/posts/index.rb
class Api::V1::Posts::Index < ControllerService
def call
scope = add_joins(initial_scope)
scope = add_filter(scope)
add_order(scope)
end
private
def add_joins(scope)
scope.joins(:author)
end
def add_filter(scope)
scope.where(author: { city: params[:author_city] })
end
def add_order(scope)
scope.order(created_at: :desc)
end
end
- For
create
action inservices/api/v1/posts/create.rb
class Api::V1::Posts::Create < ControllerService
def call
target_model.create!(post_params)
# some another logic
end
private
def post_params
@post_params ||= params.require(:post).permit(:title, :body)
end
end
- For
destroy
action inservices/api/v1/posts/destroy.rb
class Api::V1::Posts::Destroy < ControllerService
def call
post.destroy!
# some another logic
end
private
def post
@post ||= initial_scope.find(params[:id])
end
end
You need to include ApiServiceC8r::ServiceMethods
to your services.
For convenience you can create some parent service and inherit your actions services from it.
For example services/api/v1/controller_service.rb
class Api::V1::ControllerService
include ApiServiceC8r::ServiceMethods
end
target_model
- your target modelcontroller
- controller instanceinitial_scope
- scope of data whichparams
- params which you passed with requestrequest
- request instanceresponse
- response instancecurrent_user
- current userkwargs
- another arguments passed withaction
method
You can use another pagination library or serialize library
Create config/initializers/api_service_c8r.rb
ApiServiceC8r.configure do |config|
config.serializer = :another_serializer_library
config.pagination = :another_pagination_library
end
The gem is available as open source under the terms of the MIT License.