During a recent coding challenge, we were asked to add a filtering functionality to our rails application. I was stumped and scoured the documentation and forums for a quick solution to my problem. I was able to find something that worked in a pinch, but it left me really wanting to understand the best and most dry way to add this element to an app. After a bit of research, I found this to be the easiest and most user-friendly way to add a search bar to any rails application.
Step 1: Set up your rails app
First things first, make sure your rails application is functional and working correctly. Your MVC structure should be correctly implemented and migrations and associations should be completed. Seeded data is optional, but helpful to ensure that everything is running smoothly.
For this example, we'll be using a MVC structure of different types of sushi!
Sushi has many fish, and fish belongs to sushi.
On our fish index page (views/fish/index.html.erb) we want to be able to find out what kinds of fish we will need to make a particular type of sushi roll. This means that initially all of the fish instances would be displayed, but upon searching, only the fish needed to make our particular roll we be displayed.
We will need to add different elements to each part of our MVC structure in order to have the search function work correctly. I'll go in order of MVC just for clarity, but know that each of these following steps can be done in any order or however you see fit.
Step 2: (M) Add method to model
We will need to add a search method to our model page, our fish class in this example, that the controller can call on every time the search button is pressed.
We can break this down a little bit:
self: We are using self for this method as we will be calling upon the fish class to find the instances that match our parameters.
search: Search is the params[:search] that we take in as an argument that is given to us from our form implemented on the sushi index page.
Our first if statement will determine whether or not input was entered into the search form. If nothing was received and params[:search] is empty, nil will indicate false and the else statement will return all of the fish instances
- sushi_type: After passing our first if statement, we then sift through all of our sushi instances using find_by until we either find an object with the name attribute that matches our search parameters or there are no instances left to search. In the event that there are no matching instances, we will enact our else statement and return all of the fish instances per our normal index page procedure.
If we are able to find a matching sushi instance, however, we will then use that sushi object to find what fish are associated with it! Using self(or Fish).where, we will check for any fish instances that match the sushi id number previously acquired from sushi_type. This array of instances is then returned to the controller who will use it next.
Step 3: [C] Call on method in controller
Ordinarily the only index action method we would use is @fishes = Fish.all, but now we want to be able to use our search function as well as display our normal index page with all of the fish objects. In order to do this, we will edit our normal index action to include the search method we just wrote in our fish class.
This way, the search function will be invoked each time the index page is displayed. And after fully understanding our search method we know that whether search parameters are indicated or not, all of the fish instances will be shown on the fish index page.
Step 4: Permit search parameter in strong params
We need to ensure that our search parameter is permitted in order to even make a search at all! So we can go to our strong params in the fish controller and add :search.
This will ask the params for permission to allow the search key every time we call on the search method.
Step 5: [V] Add search form to index page
Sometimes this could be the first step, but there are a lot of components here that are very important to ensuring our search bar will function correctly.
form_tag: Form_tag is one of the few different embedded ruby form options we have in rails. Form_tag is especially useful when we do not want to edit any of our model attributes or aren't calling on a particular instance. In this case we simply want to sort our data and call on the index path again, which form_tag is great for. You can read more about all of the different types of forms tags in rails here in the documentation.
label_field: This is simply our label tag.
text_field_tag: This tag is important as it will be holding our search params which you know we’ve already made great use of! It is also notable that we used text_field_tag as opposed to text_field which has the possibility to manipulate our attributes.
The first :search is to indicate our search parameter as a value. The params[:search] is the key we will use later on and it also helps to allow for the search text to stay displayed in the search bar text field.
- submit_tag: Our submit tag is as simple as that, with the first attribute being the displayed text on the button. The :name => nil attribute allows for us to remove the commit keyword from our search query in the URL.
Its important to note that in our form we called on fish_index_path with a method of get. This is because we simply want to call to the index page again to show the filtered results of our search parameters. This would not be a post action as we do not want to post or add anything new to our database. (see routes below for clarification)
Step 6: Test out the search~
And there you have it! After running a rails server command in your terminal and going to your friendly localhost:3000, you’ll be able to see your new search bar in action.
I hope that this could be helpful for implementing a simple search function in your next Rails project.
Top comments (3)
Hey Megan!
Thanks for the tut!
I'm wondering about the source of this repo do you still have it?
Can you share with me?
I really want to know where does
suchi_id
come from?This is pretty old, but maybe for someone else:
Fish belongs to Sushi, so that's where :sushi_id come from. There's also controller and model for Sushi, with :id field, and that field is used as identifier in Fish controller.
Sushi would have a fields like: :id, :type..., with has_many :fishes
Thank you for this article.
It has helped me understand how to implement search features in rails.