class RailsApiModel::Filters::Field

TODO: Check whether the ActiveRecord model has the specified field

Public Instance Methods

apply_scope(relation, key, value) click to toggle source
# File lib/rails_api_model/filters/field.rb, line 5
def apply_scope(relation, key, value)
  key, modifier = key.split(':'.freeze, 2)
  value = transform_type(value)
  column = activerecord_model.arel_table[key]

  relation.where case modifier
                 when nil          then column.eq(value)
                 when 'not'.freeze then column.not_eq(value)
                 when 'lt'.freeze  then column.lt(value)
                 when 'lte'.freeze then column.lteq(value)
                 when 'gt'.freeze  then column.gt(value)
                 when 'gte'.freeze then column.gteq(value)
                 # TODO: Handle this error via Rails and send 400
                 else raise FilterError.new("Invalid modifier #{modifier}")
                 end
end

Private Instance Methods

to_boolean(value) click to toggle source
# File lib/rails_api_model/filters/field.rb, line 46
def to_boolean(value)
  case value
  # `true` is supported for arguments passed during testing
  when true, 'true'.freeze, 't'.freeze, '1'.freeze then true
  else false
  end
end
transform_type(value) click to toggle source
# File lib/rails_api_model/filters/field.rb, line 24
def transform_type(value)
  column_type = activerecord_model.columns_hash[filter_key].type

  # TODO: Verify all of these types actually exist
  # TODO: Support range queries with some syntax.
  #       Maybe `start_time:gt=2015-11-03&start_time:lt=2015-12-19`
  # TODO: Support enum values as strings
  # TODO: Support `LIKE` queries?
  case column_type
  when :string, :text then value
  # TODO: Add validation and raise error instead of silently discarding non-numbers
  when :primary_key, :integer then value.to_i
  when :float, :decimal then value.to_f
  # TODO: Smarter date parsing. Passing the date `2015-11-03` should actually
  #       make a range query `column >= 2015-11-03 and column < 2015-11-04`.
  # TODO: Catch ArgumentError for invalid dates and reraise as Rails error
  when :datetime then Time.zone.parse(value)
  when :boolean then to_boolean(value)
  else raise "Unsupported filter on column type #{column_type}"
  end
end