Resource Cheatsheet

This is an expanded version of what’s “under the hood” of a default Resource:

class EmployeeResource < ApplicationRecord
  self.model = Employee

  # JSONAPI type
  # http://jsonapi.org/format/#document-resource-identifier-objects
  self.type = :employees

  # Expanded version
  attribute :name, :string,
    readable: self.attributes_sortable_by_default,
    writable: self.attributes_sortable_by_default,
    sortable: self.attributes_sortable_by_default,
    filterable: self.attributes_sortable_by_default

  # Alter display
  # @object is your model instance
  attribute :name, :string do
    @object.name.upcase
  end

  # Default nil
  self.default_sort = [{ name: :desc }]
  # Default 10
  self.default_per_page = 10

  # Custom sort
  # sort :name, :string if no attribute defined
  sort :name do |scope, dir|
    scope.order(name: dir)
  end

  # Custom Filter
  # filter :name, :string if no attribute defined
  filter :name do
    # All of the operators here have not_ equivalents, e.q. not_eq
    # imagine ".where.not" instead of ".where"

    eq do |scope, value|
      scope.where("lower(name) IN ?", value.map(&:downcase))
    end

    eql do |scope, value|
      scope.where(name: value)
    end

    prefix do |scope, value|
      value.each do |v|
        scope = scope.where('lower(name) LIKE ?', "#{v.downcase}%")
      end
      scope
    end

    suffix do |scope, value|
      value.each do |v|
        scope = scope.where('lower(name) LIKE ?', "%#{v.downcase}")
      end
      scope
    end

    match do |scope, value|
      value.each do |v|
        scope = scope.where('lower(name) LIKE ?', "%#{v.downcase}%")
      end
      scope
    end
  end

  # Operators for integer, float, datetime, etc
  filter :age, :integer do
    eq do |scope, value|
      scope.where(age: value)
    end

    gt do |scope, value|
      value.each do |v|
        scope = scope.where('age > ?', v)
      end
      scope
    end

    gte do |scope, value|
      value.each do |v|
        scope = scope.where('age >= ?', v)
      end
      scope
    end

    lt do |scope, value|
      value.each do |v|
        scope = scope.where('age < ?', v)
      end
      scope
    end

    lte do |scope, value|
      value.each do |v|
        scope = scope.where('age <= ?', v)
      end
      scope
    end
  end

  # Will be passed to sort, filter, etc
  # Apply global logic here: only return active Employees,
  # filter results based on the current user, etc
  def base_scope
    Employee.all
  end

  # Must execute query and return an array of Model instances
  def resolve(scope)
    scope.to_a
  end

  def create(attributes)
    employee = Employee.create(attributes)
    employee.save
    employee
  end

  def update(attributes)
    employee = self.class.find(id: attributes.delete(:id))
    employee.update_attributes(attributes)
    employee
  end

  def destroy(id)
    employee = self.class.find(id: attributes.delete(:id))
    employee.destroy
    employee
  end
end