Last active
April 13, 2025 08:50
-
-
Save mamantoha/9c0aec7958c7636cebef to your computer and use it in GitHub Desktop.
Rails API Filtering and Sorting
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# app/models/experience.rb | |
# | |
# == Schema Information | |
# | |
# Table name: experiences | |
# | |
# id :integer not null, primary key | |
# title :string | |
# description :text | |
# created_at :datetime not null | |
# updated_at :datetime not null | |
# city_id :integer | |
# price :integer default(0) | |
# distance :integer | |
# duration :integer | |
# | |
class Experience < ActiveRecord::Base | |
belongs_to :city | |
has_many :categorizations | |
has_many :categories, through: :categorizations | |
scope :by_city, -> (city_ids) { where(city_id: city_ids) } | |
scope :by_price, -> (from, to) { where("price >= ? AND price <= ?", from, to) } | |
scope :by_duration, -> (from, to) { where("duration >= ? AND duration <= ?", from, to) } | |
scope :by_distance, -> (from, to) { where("distance >= ? AND distance <= ?", from, to) } | |
scope :by_category, -> (category_ids) { joins(:categories).where(categories: { id: category_ids }) } | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# app/serializers/experience_serializer.rb | |
class ExperienceSerializer < ActiveModel::Serializer | |
attribute :id | |
attribute :title | |
attribute :description | |
attribute :price | |
attribute :distance | |
attribute :duration | |
belongs_to :city | |
has_many :categories | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# app/controllers/api/v1/experiences_controller.rb | |
class Api::V1::ExperiencesController < Api::V1::BaseController | |
include Orderable | |
before_filter :authenticate_user! | |
# Filters: | |
# /api/v1/experiences?by_price[from]=100&by_price[to]=999 | |
# /api/v1/experiences?by_category=1,2,3 | |
# /api/v1/experiences?by_city=1,2,3 | |
# /api/v1/experiences?by_duration[from]=10&by_duration[to]=60 | |
# | |
has_scope :by_category, only: :index | |
has_scope :by_city, only: :index | |
has_scope :by_price, using: [:from, :to], only: :index | |
has_scope :by_duration, using: [:from, :to], only: :index | |
has_scope :by_distance, using: [:from, :to], only: :index | |
# GET /api/v1/experiences | |
def index | |
@experiences = | |
apply_scopes(Experience) | |
.order(ordering_params(params)) | |
.includes(:city, :user, :categories) | |
.all | |
render json: @experiences | |
end | |
end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# app/controllers/concerns/orderable.rb | |
module Orderable | |
extend ActiveSupport::Concern | |
module ClassMethods | |
end | |
# A list of the param names that can be used for ordering the model list | |
def ordering_params(params) | |
# For example it retrieves a list of experiences in descending order of price. | |
# Within a specific price, older experiences are ordered first | |
# | |
# GET /api/v1/experiences?sort=-price,created_at | |
# ordering_params(params) # => { price: :desc, created_at: :asc } | |
# Experience.order(price: :desc, created_at: :asc) | |
# | |
ordering = {} | |
if params[:sort] | |
sort_order = { '+' => :asc, '-' => :desc } | |
sorted_params = params[:sort].split(',') | |
sorted_params.each do |attr| | |
sort_sign = (attr =~ /\A[+-]/) ? attr.slice!(0) : '+' | |
model = controller_name.classify.constantize | |
if model.attribute_names.include?(attr) | |
ordering[attr] = sort_order[sort_sign] | |
end | |
end | |
end | |
ordering | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@mamantoha Yes, the sign will be
+
by default, but my diff covers the case where the client sends an unencoded+
(instead of a URL encoded%2B
). Consider these two request URLs:http://my.server.com/route/action?sort=%2Bcreated_at
(The%2B
gets decoded as a plus+
)http://my.server.com/route/action?sort=+created_at
(The+
gets decoded as a space" "
)My diff covers the second case.