Searching and Sorting with Ransack

In this article, we will discuss an easier way to search and sort in Rails, using a gem called ransack.

First, do some basic setup:

1
2
3
4
5
rails new ransack-app
rails db:create
rails g model Author name
rails g scaffold Post title body:text author:references
rails db:migrate

In your gemfile, add:

1
2
3
# Gemfile

gem 'ransack'

Make a relation with posts in Author.

1
2
3
# app/models/author.rb

has_many :posts

Now seed in some data.

1
2
3
4
5
6
7
8
9
10
11
# db/seeds.rb
Author.create(name: 'William Shakespeare')
Author.create(name: 'George Eliot')

Post.create(title: 'Wisdom', body: 'Some are born great, some achieve greatness, and some have greatness thrust upon them.', author_id: 1)
Post.create(title: 'Wisdom', body: 'A fool thinks himself to be wise, but a wise man knows himself to be a fool.', author_id: 1)
Post.create(title: 'Love', body: 'The course of true love never did run smooth.', author_id: 1)

Post.create(title: 'Love', body: 'Blessed is the influence of one true, loving human soul on another.', author_id: 2)
Post.create(title: 'Life', body: 'The world is full of hopeful analogies and handsome, dubious eggs, called possibilities.', author_id: 2)
Post.create(title: 'Wisdom', body: 'It will never rain roses: when we want to have more roses we must plant more trees.', author_id: 2)

In app/controllers/posts_controller.rb, update the index method.

1
2
3
4
5
6
# app/controllers/posts_controller.rb

def index
  @q = Post.ransack(params[:q])
  @posts = @q.result.includes(:author)
end

Now in app/views/posts/index.html.erb, add the following form:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# app/views/posts/index.html.erb

<%= search_form_for @q do |f| %>
 <%= f.label :title_cont %>
 <%= f.search_field :title_cont %>

 <%= f.label :body_cont %>
 <%= f.search_field :body_cont %>

 <%= f.label :author_name_cont %>
 <%= f.search_field :author_name_cont %>

 <%= f.submit %>
<% end %>

Now you will be able to search the posts by title, body text and author name.

Now, let’s jump to the second part - sorting.

In app/views/posts/index.html.erb, update the table as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# app/views/posts/index.html.erb

<table>
 <thead>
   <tr>
     <th><%= sort_link(@q, :title, 'Title', default_order: :desc) %></th>
     <th>Body</th>
     <th><%= sort_link(@q, :author_name, 'Author', default_order: :desc) %></th>
     <th><%= sort_link(@q, :created_at, 'Created', default_order: :desc) %></th>
     <th colspan="3"></th>
   </tr>
 </thead>

 <tbody>
   <% @posts.each do |post| %>
     <tr>
       <td><%= post.title %></td>
       <td><%= post.body %></td>
       <td><%= post.author.name %></td>
       <td><%= post.created_at %></td>
       <td><%= link_to 'Show', post %></td>
       <td><%= link_to 'Edit', edit_post_path(post) %></td>
       <td><%= link_to 'Destroy', post, method: :delete, data: { confirm: 'Are you sure?' } %></td>
     </tr>
   <% end %>
 </tbody>
</table>

Now the links will be sorted. Happy searching and sorting!