Generate the Unit Model and Views for the Learn to Code Rails App


In this lesson we will use the rails generate command to once again create a lot of the files we will need for another model object. This time the name of the object will be Unit. A unit will consist of a title attribute that is a string data type and also a description attribute that is a text data type. One new fold we will bring into the mix here is that the Unit object will belong to the Course object already present in our application. To represent this to the rails generate command we will use the object name flag followed by the references flag. This will create an attribute on the Unit model object called course_id and that will tie the Unit object to the Course object with the corresponding id attribute. Remember, to create the controller and views to go with the model we need to generate the scaffold:

rails g scaffold Unit title:string description:text course:references 

followed by

rake db:migrate

Rails has generated a ton of the code we need to start working with Unit objects in our application. The first thing we can do to get the most gains in improving this process is changing up the Unit object's form to allow us to select from existing Course objects to tie our Units to. Right now we have to manually type the id attribute of the Course object. It's not very practical to know the id attribute of a Course object, but we are likely to recognize a Course object's name attribute if it were in a list we could choose from.

This can be accomplished with the select HTML tag. Since it's so common to list Ruby objects as option tags inside a select tag Rails actually offers us another helper method to make the whole process extremely simple.

Using Rails select helper method

Breaking this code down:

<%= f.label :Course %>

will create the HTML


There's a little more to unpack in the next line

<%= select("unit", "course_id", Course.all.collect { |p| [p.title,] }, {prompt: 'Select Course'}, class: 'form-control') %>

select is a Rails helper method that will output a select tag. The first argument, "unit", is telling the select method that this particular input is for the Unit object and the second argument, "course_id", tells the method it's the course_id attribute of the Unit object. The third argument is probably where things get a little hazy.

Course.all.collect { |p| [p.title,] }

could also be written as

Course.all.collect do |course|

Assuming we have two Course objects, one with an id attribute of 1 and a title attribute of Build a Rails App and another with an id attribute of 2 and a title attribute of Learn Something Else, the collect method would iterate over every Course object, perform the code inside the block (what's between the do and end or the { }'s), push that return revalue to an array and return the array containing all those return values.

The result of the code above on our two example Course objects would be:

  ["Build a Rails App", 1],
  ["Learn Something Else", 2]

The rails select method takes the array above, iterates over each inner-array and says create an option HTML tag with the value html attribute equal to the object in the array at index 1 (the second object in the array) and make the inner-text of the option HTML tag the the object in the array at index 0.

The fourth argument,

{prompt: 'Select Course'}

just tells the select tag to render with a prompt for the user to select one of the available courses. The final argument should look very familiar, It's just assigning a few classes to the HTML tag.

Now our table knows about the association between a Course object and a Unit object but we need to let our Rails application know about the association as well. The way we do that is by going into the app/models/course.rb file and adding

has_many :units

the rails generate command wrote the following in our app/models/unit.rb file because we told it it referenced the Course object.

belongs_to :course

If we visit the /units path of our application and start clicking around the links scaffolding has provided for us we can create a new Unit object. When the object is created and we are redirected to the Unit object's show page we'll see that Course object we tied to it is actually being displayed itself. The Course object really isn't useful to us as humans, so let's have the show view display the Course object's title instead.

Displaying the Course title for a unit

There are a couple things we need to do to finish up. These tasks are refreshers from previous lessons. First  we need to apply the FriendlyID system to our Unit model. The process is exactly the same as it was with Course model so refer back to that listen if you need a refresher. Also like we did with the Course model, we want to add presence validations for the title and description attributes. Once again, refer to the previous lesson if you need a reminder.

Happy coding!!!!