class Hippo::API::ControllerBase
The Controller handles querying models using either pre-defined scopes or hash based queries; and also including optional associations with the reply
It assigns the following meaning the these parameters.
* f: (fields) Include the following fields (usually methods) with the reply * w: (with) Uses the defined scope to query and/or add extra data to the model * q: (query) Query the model using fields and values it is an array of clauses, which can be either forms { field: value }, or { field: { op: 'like', value: 'value%' } } * i: (include) Include associations along with the model in the reply * o: (order) Order by, { field => "ASC|DESC" } * l: (limit) Limit the returned rows to the count * s: (start) Start the query at the given offset (for paging) * df: (data format) Should data be returned as 'object' (default) or 'array'
The parameters are deliberately shortened so they can be used in query parameters without blowing the URL up to an unacceptable length
Attributes
data[R]
model[R]
params[R]
Public Class Methods
new(model, authentication, params, data={})
click to toggle source
# File lib/hippo/api/controller_base.rb, line 29 def initialize(model, authentication, params, data={}) @model = model @params = params @data = data @authentication = authentication end
Protected Instance Methods
add_access_limits_to_query(query)
click to toggle source
query options
# File lib/hippo/api/controller_base.rb, line 185 def add_access_limits_to_query(query) if model.respond_to?(:access_limits_for_query) model.access_limits_for_query(query, current_user, params) else query end end
add_modifiers_to_query(query)
click to toggle source
# File lib/hippo/api/controller_base.rb, line 212 def add_modifiers_to_query(query) query = query.limit(query_limit_size) query = query.offset(query_offset.to_i) if query_offset.present? if include_associations.any? allowed_includes = include_associations.each_with_object([]) do |desired, results| if desired.is_a?(Hash) nested = {} desired.each do |name, sub_associations| nested[name.to_sym] = sub_associations if model.has_exported_association?(name, current_user) end results.push(nested) unless nested.empty? else results.push(desired.to_sym) if model.has_exported_association?(desired, current_user) end end query = query.includes(allowed_includes) unless allowed_includes.empty? end if sort_order.present? sort_order.each do |fld, dir| query = model.append_sort_to_query( query, fld, dir.downcase.to_sym ) end end query end
add_params_to_query(query)
click to toggle source
# File lib/hippo/api/controller_base.rb, line 254 def add_params_to_query(query) query_params.each do |field, value| next unless (field = convert_field_to_arel(field)) if value.is_a?(Hash) && value.key?('value') op = value['op'] value = value['value'] end query = query.where( field_to_predicate(field, value, op) ) end query end
add_scope_to_query(query)
click to toggle source
# File lib/hippo/api/controller_base.rb, line 244 def add_scope_to_query(query) query_scopes.each do |name, arg| next unless model.has_exported_scope?(name, current_user) args = [name] args.push(arg) unless arg.blank? query = query.send(*args) end query end
add_scopes_to_query(query)
click to toggle source
# File lib/hippo/api/controller_base.rb, line 207 def add_scopes_to_query(query) query = add_scope_to_query(query) if query_scopes.present? query end
build_allowed_associations(association, model_class = self.model)
click to toggle source
# File lib/hippo/api/controller_base.rb, line 156 def build_allowed_associations(association, model_class = self.model) includes = {} if association.is_a?(Hash) association.each do |include_name, sub_associations| if model_class.has_exported_association?(include_name, current_user) && (reflection = model_class.reflect_on_association(include_name.to_sym)) sub_includes = includes[include_name.to_sym] = {} allowed = build_allowed_associations(sub_associations, reflection.klass) unless allowed.empty? sub_includes[:include] ||= [] sub_includes[:include] << allowed end end end elsif association.is_a?(Array) association.each do |sub_association| if model_class.has_exported_association?(sub_association, current_user) includes.merge! build_allowed_associations(sub_association, model_class) end end else includes[association.to_sym] = {} if model_class.has_exported_association?(association, current_user) end includes end
build_query(query = model.all)
click to toggle source
# File lib/hippo/api/controller_base.rb, line 193 def build_query(query = model.all) query = query.where(id: params[:id]) if params[:id] if params[:nested_attribute] query = query.where(params[:nested_attribute]) end query = add_access_limits_to_query(query) query = add_params_to_query(query) if query_params.present? query end
build_reply_options()
click to toggle source
Extract options that are suitable for use in 'as_json'
# File lib/hippo/api/controller_base.rb, line 139 def build_reply_options options = {} if include_associations.any? options[:include] = include_associations.each_with_object({}) do |association, includes| includes.merge! build_allowed_associations(association) end end if requested_fields.any? options[:methods] = requested_fields.select do |f| model.has_exported_method?(f, current_user) end end options[:format] = reply_with_array? ? 'array' : 'object' options end
convert_field_to_arel(field)
click to toggle source
# File lib/hippo/api/controller_base.rb, line 268 def convert_field_to_arel(field) if field.include?('.') (table_name, field_name) = field.split('.') if model.has_exported_join_table?(table_name, current_user) Arel::Table.new(table_name)[field_name] else nil end elsif model.attribute_method?(field) model.arel_table[field] else Arel::Nodes::SqlLiteral.new( model.connection.quote_column_name(field) ) end end
count_query_records(query)
click to toggle source
# File lib/hippo/api/controller_base.rb, line 203 def count_query_records(query) query.unscope(:select).count end
current_user()
click to toggle source
# File lib/hippo/api/controller_base.rb, line 38 def current_user @current_user ||= @authentication.current_user end
field_to_predicate(field, value, op = nil)
click to toggle source
complete list: github.com/rails/arel/blob/master/lib/arel/predications.rb
# File lib/hippo/api/controller_base.rb, line 286 def field_to_predicate(field, value, op = nil) case op when nil, 'eq' then field.eq(value) when 'like' then field.matches(value) when 'ne' then field.not_eq(value) when 'lt' then field.lt(value) when 'in' then field.in(Range.new(*value)) when 'gt' then field.gt(value) when 'between' then field.between(Range.new(*value.split('...'))) else value =~ /%/ ? field.matches(value) : field.eq(value) end end
include_associations()
click to toggle source
# File lib/hippo/api/controller_base.rb, line 114 def include_associations [*params[:i]] end
max_query_results_size()
click to toggle source
# File lib/hippo/api/controller_base.rb, line 240 def max_query_results_size 250 # should be enough for everybody, amirite? end
perform_multiple_destroy()
click to toggle source
# File lib/hippo/api/controller_base.rb, line 63 def perform_multiple_destroy query = model.where(id: data.map { |rec| rec['id'] }) query = add_access_limits_to_query(query) success = true query.each do |record| if current_user.can_delete?(record, record.id) success = false unless record.destroy end end options = build_reply_options.merge(success: success) std_api_reply(:destroy, query, options) end
perform_multiple_updates()
click to toggle source
# File lib/hippo/api/controller_base.rb, line 76 def perform_multiple_updates query = model.where(id: data.map { |rec| rec['id'] }) query = add_access_limits_to_query(query) success = true query.each do |record| record_data = data.detect { |rd| rd['id'] == record.id } next unless record_data if current_user.can_write?(record, record.id) record.set_attribute_data(record_data, current_user) success = false unless record.save end end options = build_reply_options.merge(success: success) std_api_reply(:update, query, options) end
perform_retrieval()
click to toggle source
# File lib/hippo/api/controller_base.rb, line 42 def perform_retrieval query = build_query query = add_scopes_to_query(query) query = add_access_limits_to_query(query) options = build_reply_options if should_include_total_count? options[:total_count] = count_query_records(query) end query = add_modifiers_to_query(query) query = query.first! if params[:id] std_api_reply(:retrieve, query, options) end
perform_single_destroy()
click to toggle source
# File lib/hippo/api/controller_base.rb, line 55 def perform_single_destroy query = model.where(id: params[:id]) query = add_access_limits_to_query(query) record = query.first! record.destroy std_api_reply(:destroy, record, {}) end
perform_single_update()
click to toggle source
# File lib/hippo/api/controller_base.rb, line 92 def perform_single_update query = build_query query = add_access_limits_to_query(query) record = query.first! record.set_attribute_data(data, current_user) options = build_reply_options.merge(success: record.save) std_api_reply(:update, record, options) end
query_limit_size()
click to toggle source
# File lib/hippo/api/controller_base.rb, line 120 def query_limit_size limit = max_query_results_size requested_limit ? [requested_limit, limit].min : limit end
query_offset()
click to toggle source
# File lib/hippo/api/controller_base.rb, line 124 def query_offset params[:s] end
query_params()
click to toggle source
# File lib/hippo/api/controller_base.rb, line 111 def query_params params[:q] end
query_scopes()
click to toggle source
# File lib/hippo/api/controller_base.rb, line 108 def query_scopes [*params[:w]] end
reply_with_array?()
click to toggle source
# File lib/hippo/api/controller_base.rb, line 105 def reply_with_array? params[:df] == 'array' end
requested_fields()
click to toggle source
@return [Array<String>] The fields to include in query. May represent either an attribute or a method
# File lib/hippo/api/controller_base.rb, line 102 def requested_fields [*params[:f]] end
requested_limit()
click to toggle source
# File lib/hippo/api/controller_base.rb, line 127 def requested_limit params.key?(:l) ? params[:l].to_i : nil end
should_include_total_count?()
click to toggle source
Should the result include the total number of available records
# File lib/hippo/api/controller_base.rb, line 134 def should_include_total_count? requested_limit && params[:id].blank? end
sort_order()
click to toggle source
# File lib/hippo/api/controller_base.rb, line 117 def sort_order params[:o] end