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.
Top comments (0)