1- class Api ::V1 ::BaseController < ApplicationController
2- include Authenticatable
3- include Pundit ::Authorization
4-
5- # Skip authentication for specific actions if needed
6- # This will be overridden in individual controllers
7-
8- rescue_from ActiveRecord ::RecordNotFound , with : :render_not_found
9- rescue_from ActiveRecord ::RecordInvalid , with : :render_validation_errors
10- rescue_from ActionController ::ParameterMissing , with : :render_parameter_missing
11- rescue_from Pundit ::NotAuthorizedError , with : :render_forbidden_policy
12-
13- protected
14-
15- def render_success ( data = { } , message : nil , status : :ok )
16- response = { }
17- response [ :message ] = message if message
18- response [ :data ] = data if data . present?
19-
20- render json : response , status : status
21- end
22-
23- def render_created ( data = { } , message : 'Resource created successfully' )
24- render_success ( data , message : message , status : :created )
25- end
26-
27- def render_updated ( data = { } , message : 'Resource updated successfully' )
28- render_success ( data , message : message , status : :ok )
29- end
30-
31- def render_deleted ( message : 'Resource deleted successfully' )
32- render json : { message : message } , status : :ok
33- end
34-
35- def render_error ( message :, code : 'ERROR' , status : :bad_request , details : nil )
36- error_response = {
37- error : {
38- code : code ,
39- message : message
40- }
41- }
42-
43- error_response [ :error ] [ :details ] = details if details
44-
45- render json : error_response , status : status
46- end
47-
48- def render_validation_errors ( exception )
49- render_error (
50- message : 'Validation failed' ,
51- code : 'VALIDATION_ERROR' ,
52- status : :unprocessable_entity ,
53- details : exception . record . errors . as_json
54- )
55- end
56-
57- def render_not_found ( exception = nil )
58- resource_name = exception &.model &.humanize || 'Resource'
59- render_error (
60- message : "#{ resource_name } not found" ,
61- code : 'NOT_FOUND' ,
62- status : :not_found
63- )
64- end
65-
66- def render_parameter_missing ( exception )
67- render_error (
68- message : "Missing required parameter: #{ exception . param } " ,
69- code : 'PARAMETER_MISSING' ,
70- status : :bad_request
71- )
72- end
73-
74- def paginate ( collection , per_page : 20 )
75- page = params [ :page ] &.to_i || 1
76- per_page = [ params [ :per_page ] &.to_i || per_page , 100 ] . min # Max 100 per page
77-
78- paginated = collection . page ( page ) . per ( per_page )
79-
80- {
81- data : paginated ,
82- pagination : {
83- current_page : paginated . current_page ,
84- per_page : paginated . limit_value ,
85- total_pages : paginated . total_pages ,
86- total_count : paginated . total_count ,
87- has_next_page : paginated . next_page . present? ,
88- has_prev_page : paginated . prev_page . present?
89- }
90- }
91- end
92-
93- def log_user_action ( action :, entity_type :, entity_id : nil , old_values : { } , new_values : { } )
94- AuditLog . create! (
95- organization : current_organization ,
96- user : current_user ,
97- action : action . to_s ,
98- entity_type : entity_type . to_s ,
99- entity_id : entity_id ,
100- old_values : old_values ,
101- new_values : new_values ,
102- ip_address : request . remote_ip ,
103- user_agent : request . user_agent
104- )
105- end
106-
107- private
108-
109- def set_content_type
110- response . content_type = 'application/json'
111- end
112-
113- def render_forbidden_policy ( exception )
114- policy_name = exception . policy . class . to_s . underscore
115- render_error (
116- message : "You are not authorized to perform this action" ,
117- code : 'FORBIDDEN' ,
118- status : :forbidden ,
119- details : {
120- policy : policy_name ,
121- action : exception . query
122- }
123- )
124- end
125- end
1+ # frozen_string_literal: true
2+
3+ module Api
4+ module V1
5+ class BaseController < ApplicationController
6+ include Authenticatable
7+ include Pundit ::Authorization
8+
9+ # Skip authentication for specific actions if needed
10+ # This will be overridden in individual controllers
11+
12+ rescue_from ActiveRecord ::RecordNotFound , with : :render_not_found
13+ rescue_from ActiveRecord ::RecordInvalid , with : :render_validation_errors
14+ rescue_from ActionController ::ParameterMissing , with : :render_parameter_missing
15+ rescue_from Pundit ::NotAuthorizedError , with : :render_forbidden_policy
16+
17+ protected
18+
19+ def render_success ( data = { } , message : nil , status : :ok )
20+ response = { }
21+ response [ :message ] = message if message
22+ response [ :data ] = data if data . present?
23+
24+ render json : response , status : status
25+ end
26+
27+ def render_created ( data = { } , message : 'Resource created successfully' )
28+ render_success ( data , message : message , status : :created )
29+ end
30+
31+ def render_updated ( data = { } , message : 'Resource updated successfully' )
32+ render_success ( data , message : message , status : :ok )
33+ end
34+
35+ def render_deleted ( message : 'Resource deleted successfully' )
36+ render json : { message : message } , status : :ok
37+ end
38+
39+ def render_error ( message :, code : 'ERROR' , status : :bad_request , details : nil )
40+ error_response = {
41+ error : {
42+ code : code ,
43+ message : message
44+ }
45+ }
46+
47+ error_response [ :error ] [ :details ] = details if details
48+
49+ render json : error_response , status : status
50+ end
51+
52+ def render_validation_errors ( exception )
53+ render_error (
54+ message : 'Validation failed' ,
55+ code : 'VALIDATION_ERROR' ,
56+ status : :unprocessable_entity ,
57+ details : exception . record . errors . as_json
58+ )
59+ end
60+
61+ def render_not_found ( exception = nil )
62+ resource_name = exception &.model &.humanize || 'Resource'
63+ render_error (
64+ message : "#{ resource_name } not found" ,
65+ code : 'NOT_FOUND' ,
66+ status : :not_found
67+ )
68+ end
69+
70+ def render_parameter_missing ( exception )
71+ render_error (
72+ message : "Missing required parameter: #{ exception . param } " ,
73+ code : 'PARAMETER_MISSING' ,
74+ status : :bad_request
75+ )
76+ end
77+
78+ def paginate ( collection , per_page : 20 )
79+ page = params [ :page ] &.to_i || 1
80+ per_page = [ params [ :per_page ] &.to_i || per_page , 100 ] . min # Max 100 per page
81+
82+ paginated = collection . page ( page ) . per ( per_page )
83+
84+ {
85+ data : paginated ,
86+ pagination : {
87+ current_page : paginated . current_page ,
88+ per_page : paginated . limit_value ,
89+ total_pages : paginated . total_pages ,
90+ total_count : paginated . total_count ,
91+ has_next_page : paginated . next_page . present? ,
92+ has_prev_page : paginated . prev_page . present?
93+ }
94+ }
95+ end
96+
97+ def log_user_action ( action :, entity_type :, entity_id : nil , old_values : { } , new_values : { } )
98+ AuditLog . create! (
99+ organization : current_organization ,
100+ user : current_user ,
101+ action : action . to_s ,
102+ entity_type : entity_type . to_s ,
103+ entity_id : entity_id ,
104+ old_values : old_values ,
105+ new_values : new_values ,
106+ ip_address : request . remote_ip ,
107+ user_agent : request . user_agent
108+ )
109+ end
110+
111+ private
112+
113+ def set_content_type
114+ response . content_type = 'application/json'
115+ end
116+
117+ def render_forbidden_policy ( exception )
118+ policy_name = exception . policy . class . to_s . underscore
119+ render_error (
120+ message : 'You are not authorized to perform this action' ,
121+ code : 'FORBIDDEN' ,
122+ status : :forbidden ,
123+ details : {
124+ policy : policy_name ,
125+ action : exception . query
126+ }
127+ )
128+ end
129+ end
130+ end
131+ end
0 commit comments