require 'inherited_resources' module Softwear module Library class ApiController < ActionController::Base include ::InheritedResources::Actions include ::InheritedResources::BaseHelpers extend ::InheritedResources::ClassMethods extend ::InheritedResources::UrlHelpers skip_before_filter :authenticate_user! skip_before_filter :verify_authenticity_token before_filter :allow_origin respond_to :json self.responder = InheritedResources::Responder self.class_attribute :resource_class, :instance_writer => false unless self.respond_to? :resource_class self.class_attribute :parents_symbols, :resources_configuration, :instance_writer => false def self.base_class Softwear::Library::ApiController end def self.token_authenticate(user_class, options = {}) include Softwear::Auth::TokenAuthentication self.user_class = user_class self.token_auth_options = options prepend_before_filter :token_authenticate_user! end def index(&block) yield if block_given? key_values = (permitted_attributes + [:id]).uniq.map do |a| [a, params[a]] if params[a] end .compact self.records ||= resource_class self.records = records.where(Hash[key_values]) respond_to do |format| format.json(&render_json(records)) end end def show super do |format| format.json(&render_json) end end def update self.record = resource_class.find(params[:id]) permitted_attributes.each do |a| begin record.send("#{a}=", params[a]) if params[a] rescue ActiveRecord::AssociationTypeMismatch # If you try to send "job" as an attribute to order, we're assuming it's # not intentional. Send "job_attributes" or update the job model separately # to actually update the job. end end if record.save respond_to { |format| format.json(&render_json) } else respond_to { |format| format.json(&render_errors) } end end def create create! do |success, failure| success.json do headers['Location'] = resource_url(record.id) render_json(status: 201).call end failure.json(&render_errors) end end def options head(:ok) if request.request_method == 'OPTIONS' end protected def base_class self.class.base_class end def render_json(options = {}) proc do if options.is_a?(Hash) records = nil else records = options options = {} end rendering = { json: (records || record), methods: (['id'] + permitted_attributes).uniq, include: includes } .merge(options) render rendering end end def render_errors(options = {}) proc do Rails.logger.error "API #{record.class.name} ERROR: #{record.errors.full_messages}" rendering = { json: { errors: record.errors }, status: :unprocessable_entity } .merge(options) render rendering end end def self.model_name name.gsub('Api::', '').gsub('Controller', '').singularize end # Override this to specify the :include option of rendering json. def includes {} end def records instance_variable_get("@#{resource_class.model_name.collection}") end def records=(r) instance_variable_set("@#{resource_class.model_name.collection}", r) end def record instance_variable_get("@#{resource_class.model_name.element}") end def record=(r) instance_variable_set("@#{resource_class.model_name.element}", r) end def allow_origin headers['Access-Control-Allow-Origin'] = '*' headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, PATCH, DELETE' headers['Access-Control-Allow-Headers'] = 'X-Requested-With' headers['Access-Control-Allow-Credentials'] = 'true' end def permitted_attributes resource_class.column_names + ['state_event'] end def permitted_params { resource_class.model_name.element => permitted_attributes } end end end end