module StandardAPI::Controller
Public Class Methods
included(klass)
click to toggle source
# File lib/standard_api/controller.rb, line 6 def self.included(klass) klass.helper_method :includes, :orders, :model, :models, :resource_limit, :default_limit klass.before_action :set_standardapi_headers klass.rescue_from StandardAPI::ParameterMissing, with: :bad_request klass.rescue_from StandardAPI::UnpermittedParameters, with: :bad_request klass.append_view_path(File.join(File.dirname(__FILE__), 'views')) klass.extend(ClassMethods) end
Public Instance Methods
add_resource()
click to toggle source
# File lib/standard_api/controller.rb, line 125 def add_resource resource = resources.find(params[:id]) association = resource.association(params[:relationship]) subresource = association.klass.find_by_id(params[:resource_id]) if(subresource) if association.is_a? ActiveRecord::Associations::HasManyAssociation result = resource.send(params[:relationship]) << subresource else result = resource.send("#{params[:relationship]}=", subresource) end head result ? :created : :bad_request else head :not_found end end
calculate()
click to toggle source
# File lib/standard_api/controller.rb, line 37 def calculate @calculations = resources.reorder(nil).pluck(*calculate_selects).map do |c| if c.is_a?(Array) c.map { |v| v.is_a?(BigDecimal) ? v.to_f : v } else c.is_a?(BigDecimal) ? c.to_f : c end end @calculations = Hash[@calculations] if @calculations[0].is_a?(Array) && params[:group_by] render json: @calculations end
create()
click to toggle source
# File lib/standard_api/controller.rb, line 59 def create record = model.new(model_params) instance_variable_set("@#{model.model_name.singular}", record) if record.save if request.format == :html redirect_to url_for( controller: record.class.base_class.model_name.collection, action: 'show', id: record.id, only_path: true ) else render :show, status: :created end else if request.format == :html render :edit, status: :bad_request else render :show, status: :bad_request end end end
current_mask()
click to toggle source
Override if you want to support masking
# File lib/standard_api/controller.rb, line 144 def current_mask @current_mask ||= {} end
destroy()
click to toggle source
# File lib/standard_api/controller.rb, line 103 def destroy resources.find(params[:id]).destroy! head :no_content end
index()
click to toggle source
# File lib/standard_api/controller.rb, line 32 def index records = preloadables(resources.limit(limit).offset(params[:offset]).sort(orders), includes) instance_variable_set("@#{model.model_name.plural}", records) end
new()
click to toggle source
# File lib/standard_api/controller.rb, line 55 def new instance_variable_set("@#{model.model_name.singular}", model.new) if model end
remove_resource()
click to toggle source
# File lib/standard_api/controller.rb, line 108 def remove_resource resource = resources.find(params[:id]) association = resource.association(params[:relationship]) subresource = association.klass.find_by_id(params[:resource_id]) if(subresource) if association.is_a? ActiveRecord::Associations::HasManyAssociation resource.send(params[:relationship]).delete(subresource) else resource.send("#{params[:relationship]}=", nil) end head :no_content else head :not_found end end
schema()
click to toggle source
# File lib/standard_api/controller.rb, line 27 def schema Rails.application.eager_load! if !Rails.application.config.eager_load end
show()
click to toggle source
# File lib/standard_api/controller.rb, line 50 def show record = preloadables(resources, includes).find(params[:id]) instance_variable_set("@#{model.model_name.singular}", record) end
tables()
click to toggle source
# File lib/standard_api/controller.rb, line 16 def tables Rails.application.eager_load! if !Rails.application.config.eager_load tables = ApplicationController.descendants tables.select! { |c| c.ancestors.include?(self.class) && c != self.class } tables.map!(&:model).compact! tables.map!(&:table_name) render json: tables end
update()
click to toggle source
# File lib/standard_api/controller.rb, line 83 def update record = resources.find(params[:id]) instance_variable_set("@#{model.model_name.singular}", record) if record.update(model_params) if request.format == :html redirect_to url_for( controller: record.class.base_class.model_name.collection, action: 'show', id: record.id, only_path: true ) else render :show, status: :ok end else render :show, status: :bad_request end end
Private Instance Methods
bad_request(exception)
click to toggle source
# File lib/standard_api/controller.rb, line 159 def bad_request(exception) render body: exception.to_s, status: :bad_request end
calculate_selects()
click to toggle source
Used in calculate
- { count: :id }
- { count: '*' }
- { count: '*', maximum: :id, minimum: :id }
- { count: '*' }, { maximum: :id }, { minimum: :id }
- { count: '*' }
-
TODO: Sanitize (normalize_select_params(params, model))
# File lib/standard_api/controller.rb, line 314 def calculate_selects return @selects if defined?(@selects) functions = ['minimum', 'maximum', 'average', 'sum', 'count'] @selects = [] @selects << params[:group_by] if params[:group_by] Array(params[:select]).each do |select| select.each do |func, value| distinct = false column = case value when ActionController::Parameters # TODO: Add support for other aggregate expressions # https://www.postgresql.org/docs/current/sql-expressions.html#SYNTAX-AGGREGATES distinct = !value[:distinct].nil? value[:distinct] else value end if (parts = column.split(".")).length > 1 @model = parts[0].singularize.camelize.constantize column = parts[1] end column = column == '*' ? Arel.star : column.to_sym if functions.include?(func.to_s.downcase) node = (defined?(@model) ? @model : model).arel_table[column].send(func) node.distinct = distinct @selects << node end end end @selects end
default_limit()
click to toggle source
The default limit if params is no specified in a request. If this value should be less than the `resource_limit`. Return `nil` if you want the limit param to be required.
# File lib/standard_api/controller.rb, line 288 def default_limit nil end
default_orders()
click to toggle source
# File lib/standard_api/controller.rb, line 246 def default_orders nil end
excludes()
click to toggle source
# File lib/standard_api/controller.rb, line 276 def excludes @excludes ||= model_excludes end
excludes_for(klass)
click to toggle source
# File lib/standard_api/controller.rb, line 204 def excludes_for(klass) if defined?(ApplicationHelper) && ApplicationHelper.instance_methods.include?(:excludes) excludes = Class.new.send(:include, ApplicationHelper).new.excludes.with_indifferent_access excludes.try(:[], klass.model_name.singular) || [] else [] end end
includes()
click to toggle source
# File lib/standard_api/controller.rb, line 238 def includes @includes ||= StandardAPI::Includes.sanitize(params[:include], model_includes) end
limit()
click to toggle source
# File lib/standard_api/controller.rb, line 292 def limit if resource_limit limit = params.permit(:limit)[:limit]&.to_i || default_limit if !limit raise StandardAPI::ParameterMissing.new(:limit) elsif limit > resource_limit raise StandardAPI::UnpermittedParameters.new([:limit, limit]) end limit else params.permit(:limit)[:limit] end end
model()
click to toggle source
# File lib/standard_api/controller.rb, line 167 def model self.class.model end
model_excludes()
click to toggle source
# File lib/standard_api/controller.rb, line 213 def model_excludes excludes_for(model) end
model_includes()
click to toggle source
# File lib/standard_api/controller.rb, line 180 def model_includes if self.respond_to?("#{model.model_name.singular}_includes", true) self.send("#{model.model_name.singular}_includes") else [] end end
model_orders()
click to toggle source
# File lib/standard_api/controller.rb, line 188 def model_orders if self.respond_to?("#{model.model_name.singular}_orders", true) self.send("#{model.model_name.singular}_orders") else [] end end
model_params()
click to toggle source
# File lib/standard_api/controller.rb, line 196 def model_params if self.respond_to?("#{model.model_name.singular}_params", true) params.require(model.model_name.singular).permit(self.send("#{model.model_name.singular}_params")) else ActionController::Parameters.new end end
models()
click to toggle source
# File lib/standard_api/controller.rb, line 171 def models return @models if defined?(@models) Rails.application.eager_load! if !Rails.application.config.eager_load @models = ApplicationController.descendants @models.select! { |c| c.ancestors.include?(self.class) && c != self.class } @models.map!(&:model).compact! end
orders()
click to toggle source
# File lib/standard_api/controller.rb, line 250 def orders exluded_required_orders = required_orders.map(&:to_s) case params[:order] when Hash, ActionController::Parameters exluded_required_orders -= params[:order].keys.map(&:to_s) when Array params[:order].flatten.each do |v| case v when Hash, ActionController::Parameters exluded_required_orders -= v.keys.map(&:to_s) when String exluded_required_orders.delete(v) end end when String exluded_required_orders.delete(params[:order]) end if !exluded_required_orders.empty? params[:order] = exluded_required_orders.unshift(params[:order]) end @orders ||= StandardAPI::Orders.sanitize(params[:order] || default_orders, model_orders | required_orders) end
required_orders()
click to toggle source
# File lib/standard_api/controller.rb, line 242 def required_orders [] end
resource_limit()
click to toggle source
The maximum number of results returned by index
# File lib/standard_api/controller.rb, line 281 def resource_limit 1000 end
resources()
click to toggle source
# File lib/standard_api/controller.rb, line 217 def resources mask = current_mask[model.table_name] || current_mask[model.table_name.to_sym] query = model.filter(params['where']).filter(mask) if params[:distinct_on] query = query.distinct_on(params[:distinct_on]) elsif params[:distinct] query = query.distinct end if params[:join] query = query.joins(params[:join].to_sym) end if params[:group_by] query = query.group(params[:group_by]) end query end
set_standardapi_headers()
click to toggle source
# File lib/standard_api/controller.rb, line 163 def set_standardapi_headers headers['StandardAPI-Version'] = StandardAPI::VERSION end