Rafał Jaroszewicz

Rails + Stimulus.js sorting filter on select

In my new project I wanted to introduce sorting on the index page for my records and I came up with this simple Stimulus.js solution.

First, I created the select

<select aria-label="select">
  <option value="id desc">Latest</option>
  <option value="id asc">Oldest</option>
  <option value="name asc">A-Z</option>
  <option value="name desc">Z-A</option>
</select>

Then once i have my element in place I can create a Stimulus controller

rails g stimulus select

And also attach it to my select

<select data-controller="select" aria-label="select">
  <!-- content -->
</select>

Now, let’s attach the action to our element that is responsible for selecting.

export default class extends Controller {
  params = new URLSearchParams(window.location.search)
  connect() {
    // attach action to the element
    this.element.dataset.action = "change->select#filter"
    // set initial params after page load
    this.element.value = this.params.get('sort')
  }
  filter() {
    const query = this.element.value
    this.params.set('sort', query)
    window.location.search = this.params.toString()
  }
}

The reason I’m setting this.element.value in my connect() method is because of the next method introduced, filter(). Here I will set the search location of the window object to the params we got from our select. However this will refresh the page and cause the select to reset.

Last step is adding the actual filtering to the controller, but to make sure that it’s safe and user cannot send their own values I also introduce an array of values available in this filter.

class Property::SalesController < ApplicationController
  before_action :set_property_sale, only: %i[ show edit update destroy ]
  SORT_METHODS = ['id asc', 'id desc', 'name asc', 'name desc']

  # GET /property/sales or /property/sales.json
  def index
    @property_sales = Property::Sale.all
    @property_sales = @property_sales.order(params[:sort]) if params[:sort].presence.in? SORT_METHODS
  end
end

Now our input is safe because only these 4 strings can trigger a database call.

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top