Upgrading Sorting and Filtering in Rails with Ransack
Upgrading Sorting and Filtering in Rails with Ransack
Ever tried building search functionality in Rails and ended up with a messy controller full of where
clauses? I’ve been there! Let me show you how Ransack can save you hours of work and make your search code actually readable.
What is Ransack?
Ransack is a gem that handles search and filtering for you. Instead of writing tons of ActiveRecord queries, you just tell Ransack what you want to search for, and it does the heavy lifting.
Setup (Rails 7.0)
Add it to your Gemfile:
# Gemfile
gem 'rails', '~> 7.0.3'
gem 'ransack', '~> 2.6'
bundle install
Let’s Build an Article Search
Here’s a simple Article model we’ll use for our example:
# app/models/article.rb
class Article < ApplicationRecord
belongs_to :author, class_name: 'User'
belongs_to :category
enum status: { draft: 0, published: 1, archived: 2 }
end
The Old Way vs The Ransack Way
Without Ransack (The Painful Way)
Look at all this code just for basic search:
# app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
def index
@articles = Article.all
# Title search
if params[:title].present?
@articles = @articles.where("title ILIKE ?", "%#{params[:title]}%")
end
# Status filter
if params[:status].present?
@articles = @articles.where(status: params[:status])
end
# Author filter
if params[:author_id].present?
@articles = @articles.where(author_id: params[:author_id])
end
# And this goes on and on...
end
end
With Ransack (The Easy Way)
# app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
def index
@q = Article.ransack(params[:q])
@articles = @q.result.includes(:author, :category)
end
end
That’s it! Just 3 lines instead of 30+.
The Search Form
<!-- app/views/articles/index.html.erb -->
<%= search_form_for @q do |f| %>
<%= f.search_field :title_cont, placeholder: "Search by title" %>
<%= f.select :status_eq, options_for_select([
['All Statuses', ''],
['Draft', 'draft'],
['Published', 'published'],
['Archived', 'archived']
]) %>
<%= f.collection_select :author_id_eq, User.all, :id, :name,
{ prompt: 'All Authors' } %>
<%= f.submit "Search" %>
<% end %>
<!-- Easy sorting links -->
<%= sort_link(@q, :title, "Title") %>
<%= sort_link(@q, :created_at, "Date") %>
Cool Ransack Tricks
Search Related Models
Want to search by author name? Easy!
<%= f.search_field :author_name_cont, placeholder: "Search by author name" %>
Different Search Types
Ransack has lots of built-in search options:
<!-- Contains (default) -->
<%= f.search_field :title_cont, placeholder: "Title contains..." %>
<!-- Starts with -->
<%= f.search_field :title_start, placeholder: "Title starts with..." %>
<!-- Equals exactly -->
<%= f.search_field :title_eq, placeholder: "Title equals..." %>
<!-- Date ranges -->
<%= f.date_field :created_at_gteq, placeholder: "From date" %>
<%= f.date_field :created_at_lteq, placeholder: "To date" %>
Why Ransack is Awesome
Less Code, More Features
- Without Ransack: 30+ lines of messy controller code
- With Ransack: 3 clean lines that do more
It’s Secure by Default
Ransack handles SQL injection protection for you. No more worrying about sanitizing user input!
Easy Sorting
<!-- Just add this and sorting works -->
<%= sort_link(@q, :title, "Title") %>
<%= sort_link(@q, :created_at, "Date") %>
Keep It Safe
You should tell Ransack which fields are okay to search:
# app/models/article.rb
class Article < ApplicationRecord
def self.ransackable_attributes(auth_object = nil)
%w[title content status created_at]
end
def self.ransackable_associations(auth_object = nil)
%w[author category]
end
end
Performance Tip
Always include your associations to avoid N+1 queries:
@articles = @q.result.includes(:author, :category)
Wrapping Up
Ransack turns complicated search code into something simple and readable. Instead of spending hours writing custom search logic, you can focus on building the features that matter.
The best part? It handles all the tricky stuff like SQL injection protection and parameter parsing automatically. Give it a try on your next Rails project - you’ll wonder how you ever built search without it!