How to Add a Drop Down Form Element in Rails 5 for Parent/Child Relationships
This guide walks through how to implement a collection_select form element that allows for a drop down select box to be shown to users. Additionally we'll integrate bootstrap styles for the drop-down box.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

I rearranged a few of these items, just because I wanted to group them together. Here, what I want to do is. I want to require a topic for blogs. Right now, we know that a blog that belongs to a topic but it's not required and that's going to be important to do for a data validation standpoint. We also want to make the topic available in the blog form page. We want to have a topic index view and a show view and then a topic widget in the blog sidebar. These are going to be 4 tasks. We'll see how far we can get through on them right now.

If I open up the topic.rb page you can see that a topic has many blogs and we're validating the presence of the title. That's good. Now if I open up the blog.rb page which is in the models directory we can come here and see that a blog belongs to topic, but we're not actually requiring it...

validates_presence_of :title, :body, :topic_id

Let's do that by passing in the topic_id. Before we can add this to the form we have to go to our blogs_controller.rb scrolling all the way down and inside our blog params if we're going to add it to the forum. We also have to add it right here.

large

I'm going to say topic_id. We are good to go. This doesn't actually change anything in the application yet. All it essentially does is let us change it. Let's start up the Rails server here and we'll go and navigate to the blog form page and from here we can plan on how we want this to look. If I click on edit and there we go. This is working. We have our regular text field and then we have our text area right here. What I'm going to do is to have a drop down in the form that allows us to pick from any of the available topics. Then we can just click on it and it will be saved. In order to do that we're going to have to open up our blogs form partial right here(_form.html.erb). We have our title our content. I want to add another form group that goes in-between these two

large

this is going to be where everything is going to go for the form element. The one thing that's going to be a little bit different is if you notice these other two fields are a text_field and then a text_area. What we want here is going to be a little bit different.

<div class="form-group">
  <%= f.label :topic_id %>
  <%= f.collection_select(:topic_id, Topic.all, :id, :title,
                                             {
                                               selected: blog.topic_id,
                                               include_blank: true
                                              },
                                              class: 'form-control'
                                            )
  %>
</div>

Let's first give it a label. I'm going to say f.label and then we can just say :topic_id. Now we're going to use a very cool little tool called the collections select method so I can say f.collection_select. This is a method provided from Rails and it's a form helper method so we can say :topic_id and that is going to let the collections select method know which attribute that we want to communicate with. Now we can say Topic.all. This is going to run a small database query and just bring back all of the topics and then we need to map the id and the title. What Topic.all is going to do is it's going to bring back all of its attributes. We want the id because that's what we want to map to our topic_id. But then we don't want to show the topic_id because imagine seeing numbers like 1, 2 and 3 we're not going to know what that maps to. We also want the title. Now inside of this, we have the ability to pass in some optional parameters and I'm going to put these on multiple levels. You can put them all on one line but I think it makes more sense to read it like this. What we're going to do now is there are some optional params. If I do selected I can say @blog and actually I don't think I need to do @blog I think I should be able to just call it blog. The reason is because this is in a partial, but it's a form for this blog. We'll see if that throws and error. Then I can say topic_id, and then include _blank set to true (include_blank: true). Then right after the {} I'm going to say class and form-control(class:'form-control'). Then one last thing is we need to actually close up our erb. I'm going to line it up so, it's right here.

OK. So that was a bit of code. Let's see if that is actually working or not. If it is then we'll come back, walk through it and see if it's doing everything we need. So, far so good. You can see that now we have a topic and it is mapped to the correct item so that's pretty cool. If I click on topic zero hit submit. This was blog post 6, now we can go see if this works. On the show page I can just print it out right now, well we're eventually going to put it in the breadcrumbs if you remember that from the task list. So, blogs/show.html.erb. Right now we're putting all of this here. I'm just going to create a kind of a temporary tag for the topic. I can say @blog.topic.title...

large

If I hit save. I've come back hit refresh, this should bring back 'Topic 0'. Perfect, now if I come back here change it to topic 1 hit submit. Now it is 'Topic 1'. This is now wired up so that from now on we can come and we can change these. Having these listed out like this doesn't really make any sense. For real practical purposes this would say something like Rails coding or coding exercises or whatever you want your blog to be about. As a review, you can do this if you want. I'm not going to create a form page for topics because I don't think we're really going to be changing a lot of topics. You totally can if you want it's not a very difficult thing to do and we've already walked through how to do it with our blogs and with our portfolio items. If I open up the Rails console here I can say...

Topic.create!(title: "Coding Exercises")

Let's do another one just to make things seem a little bit more practical so we can say...

Topic.create!(title: "Rails")

Let's start off the rails server. We now should be able to pick from these two different items in addition to our placeholder ones. If I hit refresh, I can click this and you can see we have 'coding exercises'. If I hit submit, this is now showing up as coding exercises so this is all working very nicely.

Let's come to a pivotal tracker. We have required a topic for blogs. We did that in the blog.rb file. We have a topic for blog form page element there now. So that is all good. Our next few ones are to create an index, show action and then a blog widget. I think we're going to pause the video right now. When we come back we will implement that. Let's save our progress.

git status
git add .
git commit -m "Added validations for topics in blogs and added a topic form element"
git push origin final-changes

We're good to go! In the next guide, we're going to build out a topic's controller along with the index and the show actions.

Resources