mirror of
https://github.com/we-promise/sure.git
synced 2026-04-19 12:04:08 +00:00
Add categories endpoint in API (#460)
* Add categories endpoint in API * FIX eager load parent and subcategories associations * FIX update specs to match * Add rswag spec * FIX openapi spec * FIX final warns
This commit is contained in:
98
app/controllers/api/v1/categories_controller.rb
Normal file
98
app/controllers/api/v1/categories_controller.rb
Normal file
@@ -0,0 +1,98 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Api::V1::CategoriesController < Api::V1::BaseController
|
||||
include Pagy::Backend
|
||||
|
||||
before_action :ensure_read_scope
|
||||
before_action :set_category, only: :show
|
||||
|
||||
def index
|
||||
family = current_resource_owner.family
|
||||
categories_query = family.categories.includes(:parent, :subcategories).alphabetically
|
||||
|
||||
# Apply filters
|
||||
categories_query = apply_filters(categories_query)
|
||||
|
||||
# Handle pagination with Pagy
|
||||
@pagy, @categories = pagy(
|
||||
categories_query,
|
||||
page: safe_page_param,
|
||||
limit: safe_per_page_param
|
||||
)
|
||||
|
||||
@per_page = safe_per_page_param
|
||||
|
||||
render :index
|
||||
rescue => e
|
||||
Rails.logger.error "CategoriesController#index error: #{e.message}"
|
||||
Rails.logger.error e.backtrace.join("\n")
|
||||
|
||||
render json: {
|
||||
error: "internal_server_error",
|
||||
message: "Error: #{e.message}"
|
||||
}, status: :internal_server_error
|
||||
end
|
||||
|
||||
def show
|
||||
render :show
|
||||
rescue => e
|
||||
Rails.logger.error "CategoriesController#show error: #{e.message}"
|
||||
Rails.logger.error e.backtrace.join("\n")
|
||||
|
||||
render json: {
|
||||
error: "internal_server_error",
|
||||
message: "Error: #{e.message}"
|
||||
}, status: :internal_server_error
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_category
|
||||
family = current_resource_owner.family
|
||||
@category = family.categories.includes(:parent, :subcategories).find(params[:id])
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
render json: {
|
||||
error: "not_found",
|
||||
message: "Category not found"
|
||||
}, status: :not_found
|
||||
end
|
||||
|
||||
def ensure_read_scope
|
||||
authorize_scope!(:read)
|
||||
end
|
||||
|
||||
def apply_filters(query)
|
||||
# Filter by classification (income/expense)
|
||||
if params[:classification].present?
|
||||
query = query.where(classification: params[:classification])
|
||||
end
|
||||
|
||||
# Filter for root categories only (no parent)
|
||||
if params[:roots_only].present? && ActiveModel::Type::Boolean.new.cast(params[:roots_only])
|
||||
query = query.roots
|
||||
end
|
||||
|
||||
# Filter by parent_id
|
||||
if params[:parent_id].present?
|
||||
query = query.where(parent_id: params[:parent_id])
|
||||
end
|
||||
|
||||
query
|
||||
end
|
||||
|
||||
def safe_page_param
|
||||
page = params[:page].to_i
|
||||
page > 0 ? page : 1
|
||||
end
|
||||
|
||||
def safe_per_page_param
|
||||
per_page = params[:per_page].to_i
|
||||
|
||||
case per_page
|
||||
when 1..100
|
||||
per_page
|
||||
else
|
||||
25
|
||||
end
|
||||
end
|
||||
end
|
||||
23
app/views/api/v1/categories/_category.json.jbuilder
Normal file
23
app/views/api/v1/categories/_category.json.jbuilder
Normal file
@@ -0,0 +1,23 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
json.id category.id
|
||||
json.name category.name
|
||||
json.classification category.classification
|
||||
json.color category.color
|
||||
json.icon category.lucide_icon
|
||||
|
||||
# Parent information (for subcategories)
|
||||
if category.parent.present?
|
||||
json.parent do
|
||||
json.id category.parent.id
|
||||
json.name category.parent.name
|
||||
end
|
||||
else
|
||||
json.parent nil
|
||||
end
|
||||
|
||||
# Subcategories count (for parent categories)
|
||||
json.subcategories_count category.subcategories.size
|
||||
|
||||
json.created_at category.created_at.iso8601
|
||||
json.updated_at category.updated_at.iso8601
|
||||
12
app/views/api/v1/categories/index.json.jbuilder
Normal file
12
app/views/api/v1/categories/index.json.jbuilder
Normal file
@@ -0,0 +1,12 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
json.categories @categories do |category|
|
||||
json.partial! "api/v1/categories/category", category: category
|
||||
end
|
||||
|
||||
json.pagination do
|
||||
json.page @pagy.page
|
||||
json.per_page @per_page
|
||||
json.total_count @pagy.count
|
||||
json.total_pages @pagy.pages
|
||||
end
|
||||
3
app/views/api/v1/categories/show.json.jbuilder
Normal file
3
app/views/api/v1/categories/show.json.jbuilder
Normal file
@@ -0,0 +1,3 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
json.partial! "api/v1/categories/category", category: @category
|
||||
Reference in New Issue
Block a user