Koren Leslie Cohen

  • About
  • Blog
  • Contact

33 comments

Ruby / Rails

Creating a Simple Search in Rails 4

July 20, 2014 by Koren Leslie Cohen

rails

Say you have a blog and you want the user to be able to search your posts, you will need to add methods to both your posts controller and post model, and create a corresponding search form.

1. Posts Controller

In your posts_controller.rb file, add the following to your index method:

def index
  @posts = Post.all
  if params[:search]
    @posts = Post.search(params[:search]).order("created_at DESC")
  else
    @posts = Post.all.order('created_at DESC')
  end
end
2. Post Model

In your post.rb file, add the following method:

def self.search(search)
  where("name LIKE ?", "%#{search}%") 
  where("content LIKE ?", "%#{search}%")
end

You can choose the fields you’d like your search form to query. In the above example, the search term will be run against both the name field and the content field of each post.  If the search term appears in either of those fields, there will be a match.

Note: this will work in development with SQLite. If you switch to PostgreSQL in production, you may need to change LIKE to ILIKE.

3. Search Form

In your views/posts/index.html.erb (or wherever you’d like to place the search form), add the following simple form:

<%= form_tag(posts_path, :method => "get", id: "search-form") do %>
<%= text_field_tag :search, params[:search], placeholder: "Search Posts" %>
<%= submit_tag "Search" %>
<% end %>
4. Render Results

In addition to rendering search results, it’s nice to let the user know when there are no matching results. You can accomplish this by adding the following under the above form:

<% if @posts.present? %>
  <%= render @posts %>
<% else %>
  <p>There are no posts containing the term(s) <%= params[:search] %>.</p>
<% end %>

In the above method, you are instructing your program to display the posts if there are matching posts (the above code calls a partial _post.html.erb which actually renders the results), or let the user know there are no posts containing the searched terms.

  • About
  • Latest Posts
Connect
Koren Leslie Cohen
Product manager at Facebook. Former senior product manager at Dollar Shave Club in Los Angeles and software engineer at J.Crew / Madewell in New York City. Recovering trial lawyer.
Connect
Latest posts by Koren Leslie Cohen (see all)
  • PM Career Story - April 28, 2022
  • How to Transition into Product Management - December 26, 2017
  • What I’ve Learned in My First Few Months as a Product Manager - October 14, 2015

Related Posts

Rails: Devise Redirects (and how to Customize Devise)
Mixin Ruby Modules

Share

Facebook Google+ Twitter Pinterest Email

Comments Cancel reply

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

*

code

  1. Cayo Medeiros (yogodoshi) says

    February 11, 2015 at 4:54 pm

    Hi Karen, nice tutorial!
    Just a single observation: there are two form tags on your views/posts/index.html.erb code, you can remove the tag leaving only the helper, right? =)

    Reply
    • Koren Leslie Cohen says

      February 12, 2015 at 6:29 pm

      Good catch – totally unnecessary! (Just removed)

      Reply
  2. Cayo Medeiros (yogodoshi) says

    February 11, 2015 at 4:55 pm

    *koren, sorry! =s
    Can you please edit my mistake on the previous comment? =(

    Reply
    • Koren Leslie Cohen says

      February 12, 2015 at 6:30 pm

      No worries! 😉

      Reply
  3. Keith says

    April 27, 2015 at 9:33 am

    The search method should concatenate the results or use an ‘or’ query. In Rails 4.2, it will only return results from the last where statement. Matches in the first statement are not returned.

    Reply
    • Koren Leslie Cohen says

      April 27, 2015 at 7:47 pm

      Thanks, Keith! This is just a simple search, but I’m sure readers will find this useful when creating their own searches.

      Reply
  4. Richard says

    May 21, 2015 at 10:47 am

    some reason I had to do this to get it working, anyways thanks for the help

    where(“content LIKE ? OR name LIKE ?”, “%#{search}%”, “%#{search}%”)

    Reply
    • Sharon says

      June 7, 2015 at 11:29 pm

      Thanks for this Koren! Also thanks Richard for your solution – I was very puzzled as to why only one of my where statements would work, and varying the order of the where statements changed which one would work.

      Reply
      • Koren Leslie Cohen says

        June 8, 2015 at 12:11 am

        Glad you got it working!

        Reply
  5. Alex says

    June 23, 2015 at 1:29 pm

    For some reason when I paste the Render Results, it gives me this error.

    “SQLite3::SQLException: no such column: content: SELECT “posts”.* FROM “posts” WHERE (content LIKE ‘%ok%’) ORDER BY created_at DESC

    There are no posts containing the term(s) .”
    And it highlights the “if posts.present?” part

    Reply
  6. Sérgio Toledo says

    August 28, 2015 at 11:15 am

    Hi,

    Nice tutorial!
    I think you don’t need line 2 “@posts = Post.all” in your posts_controller.rb.

    Regards.

    Reply
    • Ott says

      February 13, 2016 at 7:18 am

      Thanks for highlighting the list() meohtd. I had been pulling my hair trying to access parameters sent from jquery having names of the form “parameterName[]”. The list() meohtd turned out to be what the doctor ordered.

      Reply
    • Edwin says

      May 1, 2016 at 2:26 pm

      Yup, completely unnecessary to perform a full search for all Posts before checking if the search parameter is present. It ends up looking for posts twice whether search is present or not.

      Reply
  7. oliver yoo says

    September 3, 2015 at 3:04 am

    Hi, Koren!!
    I’m very grateful for your tutorial!
    Thanks!

    Reply
  8. Eduardo says

    September 12, 2015 at 10:48 pm

    Koren, very good. But, in the controller, maybe the first ‘@posts = Post.all’ could be removed, isn’t it?

    Reply
  9. Brandon says

    December 2, 2015 at 12:44 am

    Good stuff, though I believe that the method should be “where(“name || content LIKE ?”, “%#{search}%”)”, or else the method is just going to return results for the content search?

    Reply
    • Jonni says

      February 13, 2016 at 7:19 am

      Wow, most useful. Can’t rembmeer how many times I’ve written something like this to handle checkbox/multiple select logic. Thank you very much and keep up the good work. 🙂

      Reply
  10. dyo says

    December 13, 2015 at 3:25 pm

    Hi Koren how about if I have category_name from another table: category, how I write this on the model

    def self.search(search)
    where(“name LIKE ?”, “%#{search}%”)
    where(“category_name LIKE ?”, “%#{search}%”) ==>>
    end

    Reply
  11. Eddie Campain says

    January 12, 2016 at 3:49 pm

    This is a very helpful post! I have a question though. How would I make the search bar work if I am looking for attributes across multiple models? Your example is dealing only with the Post model, however, how would you be able to have the search bar work for another model as well, say for example I had a User model and I wanted the search bar to be able to also handle searches for user names ? Thanks 🙂

    Reply
    • Rebecca says

      June 20, 2016 at 3:29 pm

      Did anyone ever figure this out? I’m also curios about the solution.

      Reply
  12. Jim says

    March 8, 2016 at 1:05 pm

    For any other copy-paste demons out there, when copying Brandon’s “where(“name || content LIKE ?”, “%#{search}%”)”the double-quotes turned into double apostrophes or whatever so look out for that. Fixed that and now I can search on either name or zip in my rails app.I could not get Richard’s selector to work.

    Reply
  13. Bikram says

    April 27, 2016 at 9:24 am

    Awesome tutorial .:-)
    Can we get the same tutorial on live search.

    Reply
  14. Recep İnanç says

    July 23, 2016 at 4:32 am

    Hi Karen,

    I like your tutorials! But wouldn’t this be open to sql injections?

    Reply
  15. fcoders says

    July 29, 2016 at 8:47 am

    hi
    can i make a search to search for tracking number to track orders just like ups

    Reply
  16. Joshua Bartlett says

    August 3, 2016 at 12:23 pm

    Hi Koren! Thanks for this (and for your work at DSC, y’all have the best UX Design I’ve ever encountered, I’ll be a member forever)! Here’s an odd bug I’m encountering:

    I’ve retooled this for my list of customers. If I pass through a list of parameters, ie email, phone, lname, fname, etc., and a user is missing data for any of those parameters, it prevents them from being returned. So, for example, I have a customer named John Doe. If John Doe’s profile on the site is missing an email address, then a search for John or Doe won’t return him if one of the parameters is email.

    Here’s the code:

    models/customer.rb
    def self.search(search)
    where(“phone || lastName || email LIKE ?”, “%#{search}%”)
    end

    controllers/customer_controller.rb:
    def index
    if params[:search]
    @customers = Customer.search(params[:search]).order(“created_at DESC”)
    else
    @customers = Customer.all
    end
    end

    Any thoughts?

    Reply
    • kat says

      September 13, 2016 at 3:32 pm

      You could make methods for phone, lastName, and email that check for the presence of those attributes. If they’re not present, return a dummy string instead.

      This probably won’t work exactly as written but I hope it illustrates the idea.

      “`
      models/customer.rb
      def self.search(search)
      where(“phone || lastName || email LIKE ?”, “%#{search}%”)
      end

      private
      def email
      if email.present?
      email
      else
      ‘fakeemail@fake.com’
      end
      end

      //could maybe be refactored to this? not sure…
      def email
      email ||= ‘fakeemail@fake.com’
      end
      “`

      Reply
  17. Antonio nicasio says

    August 8, 2016 at 1:16 am

    thank you very helpful

    Reply
  18. Kasper says

    October 12, 2016 at 5:18 pm

    Perfect! Thank you for providing this.

    Reply
  19. Chee Ng says

    February 22, 2017 at 4:46 pm

    Very good and thank you!

    Reply
  20. David says

    August 15, 2017 at 8:23 pm

    returning ‘Post.all’ won’t be a good idea for most real world apps.

    Reply
  21. Simon says

    December 11, 2017 at 3:20 pm

    In the controller, you can drop the line 2. For the model, just reuse this code:
    class Note < ApplicationRecord
    def self.search(search)
    where("content LIKE ? OR title LIKE ?", "%#{search}%", "%#{search}%")
    end
    end

    By the way, thanks for the post and to the commenters. Got my search engine to work. +1

    Reply

Back to Blog

Trackbacks

  1. Building a Rails App – Part X (Using an API) – Even Superheros Have to do the Laundry says:
    April 5, 2017 at 5:33 pm

    […] used this blog post as my inspiration on how to implement the search.  Thus, to start with, I’m going to create […]

    Reply
  2. Building a Rails App – Part 13 (Using an API) – Even Superheros Have to do the Laundry says:
    April 29, 2017 at 9:40 am

    […] used this blog post as my inspiration on how to implement the search.  Thus, to start with, I’m going to create […]

    Reply

  • GitHub
  • Instagram
  • LinkedIn
  • RSS
  • Twitter

Looking for something?

Copyright 2023 Koren Leslie Cohen