Skip to content

Filter on joined table

Kim Røen edited this page Sep 16, 2015 · 2 revisions

Problem: You wish to filter on a column in a joined table. This may be in another resource, or simply in a one to one relationship on the model.

Solution: By default the filters append a where condition to the relation with the filter name matching a column in the primary relation. By overriding the apply_filter method you can control how the filter is applied.

An example where the User model joins in a user_extra table using a default scope:

class User < ActiveRecord::Base
  default_scope { joins("LEFT JOIN user_extras ON user_extras.user_id = users.id") }
end

class UserResource < JSONAPI::Resource
  #phone_number comes from the user_extras table
  attributes :name, :email, :phone_number, :notes

  filters :name, :email, :phone_number

  class << self
    def apply_filter(records, filter, value, options)
      case filter
        when :phone_number
          records.where('user_extras.phone_number = ?', value)
        else
          return super(records, filter, value)
      end
    end
  end
end

Note that it's also possible to have the resource perform the inclusion of the user_extras using the records method instead of using the default_scope on the model:

class User < ActiveRecord::Base
end

class UserResource < JSONAPI::Resource
  #phone_number comes from the user_extras table
  attributes :name, :email, :phone_number, :notes

  filters :name, :email, :phone_number

  class << self
    def records(options = {})
      _model_class.joins(:user_extras)
    end

    def apply_filter(records, filter, value, options)
      case filter
        when :phone_number
          records.where('user_extras.phone_number = ?', value)
        else
          return super(records, filter, value)
      end
    end
  end
end