Subscribe to the RubyPlus Screencast Feed on Apple Podcasts Now!

Simple Search Form in Rails 5

Steps

Step 1

The tasks/index.html.erb displays all the tasks.

<h1>Tasks</h1>
<table>
  <thead>
    <tr>
      <th></th>
    </tr>
  </thead>

  <tbody>
    <tr>
      <% for task in @tasks %>
        <div class='task'>
            <strong> <%= task.name %> </strong>
        </div>
        <%= link_to 'Edit', edit_task_path(task) %>
      <% end %>
     </tr>       
  </tbody>
</table>

Browse to http://localhost:3000/tasks to view all the tasks.

Step 2

Add the search form to on the tasks index page.

<%= form_tag(tasks_path) do %>
  <%= text_field_tag :term %>
  <%= submit_tag 'Search' %>
<% end %>

Search for something and click Search. You will get the error:

ActionController::ParameterMissing in TasksController#create

Step 3

Change the task_params method in tasks controller to permit the term field in the search form:

def task_params
  params.require(:task).permit(:name, :complete, :due_date, :term)
end

Step 4

Search again. The form tag generates the form html tag that uses POST by default. So search will not work. View source to see the generated html.

<form action="/tasks" accept-charset="UTF-8" method="post">
  <input name="utf8" type="hidden" value="&#x2713;" />
  <input type="hidden" name="authenticity_token" value="pRsj8YjL" />
  <input type="text" name="term" id="term" />
  <input type="submit" name="commit" value="Search" data-disable-with="Search" />
</form>

Step 5

Change the HTTP verb in the form_tag to GET:

method: :get

The search form now looks like this:

<%= form_tag(tasks_path, method: :get) do %>
  <%= text_field_tag :term %>
  <%= submit_tag 'Search' %>
<% end %>

Step 6

Reload the tasks index page in the browser. View page source.

<form action="/tasks" accept-charset="UTF-8" method="get"><input name="utf8" type="hidden" value="&#x2713;" />
  <input type="text" name="term" id="term" />
  <input type="submit" name="commit" value="Search" data-disable-with="Search" />
</form>

You now see the http method is GET.

Step 7

The tasks controller index action does the search for the tasks.

def index
  @tasks = if params[:term]
    Task.where('name LIKE ?', "%#{params[:term]}%")
  else
    Task.all
  end
end

Search for something.

Step 8

It works. But the search term is not retained in the search form. To retain the search term in the search text field, change the search form text_field_tag to include the value for the term field:

<%= form_tag(tasks_path, method: :get) do %>
  <%= text_field_tag :term, params[:term] %>
  <%= submit_tag 'Search' %>
<% end %>

Step 9

When we search, we see:

commit=Search

in the URL.

To eliminate it, set the name of the submit_tag to nil in the search form.

<%= form_tag(tasks_path, method: :get) do %>
  <%= text_field_tag :term, params[:term] %>
  <%= submit_tag 'Search', name: nil %>
<% end %>

I know it's clunky. But it works.

Step 10

Let's refactor the tasks controller index action:

def index
  @tasks = Task.search(params[:term])
end

Move the database query logic to the task model:

def self.search(term)
  if term
    where('name LIKE ?', "%#{term}%")
  else
    all
  end
end

Step 11

If you would like to order by most recent tasks, change the search method in task model.

def self.search(term)
  if term
    where('name LIKE ?', "%#{term}%").order('id DESC')
  else
    order('id DESC') 
  end
end

We use id descending in the order method to improve performance. The primary key is indexed and the search will be faster. Especially if you have lot of data.

Summary

In this article, you learned how to use a simple search form to search the database for records that has the given string in one of the columns of a table.

Watch this Article as Screencast

You can watch this as a screencast Simple Search Form in Rails 5

Sharing is Caring