1. Generate Controller for Static Pages

If we look back at our wireframes, we see that we still have to build out the "About" and "Random" page. To give you a refresher on what we are trying to build here, the "About" page will be a page that will be used to describe what the web page is all about. The "Random" page will be a page that displays an idea that will be chosen randomly.

To create these new pages, let's create a new controller called static_pages. In the terminal, let's type in the following command:

rails generate controller static_pages

This should generate the static_pages controller. Inside this controller, we are going to create two methods, the about method and the random method.

In your static_pages_controller.rb file, let's add in the following lines:

class StaticPagesController < ApplicationController
  def about

  end

  def random

  end
end

We will see why we set up these routes in a bit, so hang tight.

Next, let's set up some routes for these pages.

Let's go into our console and type rails routes to display our routing.

   Prefix Verb   URI Pattern               Controller#Action
     root GET    /                         ideas#index
    ideas GET    /ideas(.:format)          ideas#index
          POST   /ideas(.:format)          ideas#create
 new_idea GET    /ideas/new(.:format)      ideas#new
edit_idea GET    /ideas/:id/edit(.:format) ideas#edit
     idea GET    /ideas/:id(.:format)      ideas#show
          PATCH  /ideas/:id(.:format)      ideas#update
          PUT    /ideas/:id(.:format)      ideas#update
          DELETE /ideas/:id(.:format)      ideas#destroy

We see that we don't have any paths that we can use for the "About" and "Random" pages. Let's go ahead and set these up.

Let's go into our routes.rb file, which is where we can specify how the pages are routed, to hook up our new pages.

Right now, we only have two lines, root 'ideas#index' and resources :ideas. If we recall, root 'ideas#index' sets the root page, or the home page, to the index action of ideas. Additionally, resources :ideas automatically provided us with a bunch of useful links that we could use.

View this lesson to review what resources do in the routes.rb file.

For the "About" and "Random" pages, we need to add these routes in manually. To do this, under resources :ideas, add the following lines:

get 'about' => 'static_pages#about'
get 'random' => 'static_pages#random'

Let's run the rails routes command.

   Prefix Verb   URI Pattern               Controller#Action
     root GET    /                         ideas#index
    ideas GET    /ideas(.:format)          ideas#index
          POST   /ideas(.:format)          ideas#create
 new_idea GET    /ideas/new(.:format)      ideas#new
edit_idea GET    /ideas/:id/edit(.:format) ideas#edit
     idea GET    /ideas/:id(.:format)      ideas#show
          PATCH  /ideas/:id(.:format)      ideas#update
          PUT    /ideas/:id(.:format)      ideas#update
          DELETE /ideas/:id(.:format)      ideas#destroy
    about GET    /about(.:format)          static_pages#about
   random GET    /random(.:format)         static_pages#random

Notice how in the last two lines, the routes for the about and random page were added.

Now what will happen is, when a user goes to a URL with the /about URI pattern, it will trigger the about action in the static_pages controller. Similarly, when a user goes to a URL with the /random URI pattern, it will trigger the random action in the static_pages controller.

Now that we've set up these routes, let's go into our controller and set up the view for these two routes in the next lesson.

Adding About page

Under /app/views/static_pages/ make a file called about.html.erb.

This is just going to be a static page, so you can put any kind of text here. For me, I just put in a bunch of filler text for now, but it looks like this:

<h1 class="mb-5 text-4xl font-bold">About</h1>

<h4 class="mb-3 text-2xl font-bold">Share your ideas with the world and find others.</h4>

<p class="mb-3">
  Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
  tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
  quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
  consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
  cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
  proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>

<p class="mb-3">
  Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
  tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
  quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
  consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
  cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
  proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>

<p class="mb-3">
  Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
  tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
  quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
  consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
  cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
  proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>

How to Add Filler Text

Adding filler text can be incredibly useful when you want to put content in the HTML to see what it would look like with content. To generate the classic filler text "Lorem ipsum...", you can go into Sublime, start typing lorem, and then hit tab. Just like that, your "lorem ipsum" text should be generated.

Now let's add the link to this page on the navigation bar so that people can navigate to the about page easily. Go to application.html.erb.

By now, you should have a grasp on how link_to works in rails. Try and see if you can generate the link yourself.

Your navigation bar should now look like this:

<nav class="bg-white border-gray-200">
  <div class="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-1 md:p-4">
    <a href="/" class="flex items-center space-x-3 rtl:space-x-reverse">
      <span class="self-center text-2xl font-semibold whitespace-nowrap font-pacifico text-[30px] tracking-[2px] text-primary-500">Ideator</span>
    </a>
    <button data-collapse-toggle="navbar-default" type="button" class="inline-flex items-center p-2 w-10 h-10 justify-center text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200" aria-controls="navbar-default" aria-expanded="false">
        <span class="sr-only">Open main menu</span>
        <svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 17 14">
            <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h15M1 7h15M1 13h15"/>
        </svg>
    </button>
    <div class="hidden w-full md:block md:w-auto" id="navbar-default">
      <ul class="font-medium flex flex-col p-4 md:p-0 mt-4 border border-gray-100 rounded-lg bg-gray-50 md:flex-row md:space-x-8 rtl:space-x-reverse md:mt-0 md:border-0 md:bg-white">
        <li>
          <a href="#" class="block py-2 px-3 text-white bg-blue-700 rounded md:bg-transparent md:text-blue-700 md:p-0" aria-current="page">All Ideas</a>
        </li>
        <li>
          <a href="#" class="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0">Inspire Me</a>
        </li>
        <li>
          <a href="/about" class="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0">About</a>
        </li>
      </ul>
    </div>
  </div>
</nav>

Let's try this out. If you go to /about, you should see your about page. Awesome!

Let's now move on to building the "Random" page.

Adding the random page

Now that we've got the "About" page, let's add the final page - the "Random" page. On this page, we want to display one random idea from our database, and everytime a user refreshes the page, we want it to generate another random idea.

For the first few steps, let's do exactly what we did for the about page.

We're first going to create a file called random.html.erb inside /app/views/static_pages.

Then we're going to go into our static_pages_controller.rb and add the random method. In this method, we're going to try to store a random Idea into an instance variable so that we can use it in our random.html.erb.

It turns out that you can do this easily by doing this:

@idea = Idea.all.sample

What we are doing here is first ordering all of our ideas randomly. Then we are grabbing the first idea off of the randomly ordered ideas, and then storing it into @idea.

Let's now add modify the random method to in the static_pages_controller.rb to look like this:

def random
  @idea = Idea.all.sample
end

Like we've explained before, with this method called random, we can now use the instance variable @idea in our views. With this piece of code, @idea will now give us a random idea, so let's go into our random.html.erb and display this. In random.html.erb, add the following piece of code:

<%= @idea.description %>
<%= @idea.author %>

Here, we are displaying the description and author of the @idea. Remember, here @idea is assigned a random Idea.

If we go to /random, we see an idea and every time we refresh the page, a new idea comes up. Awesome!

Now we just want to put this in a card panel, like we did on the index page. We're just going to pull the code from index.html.erb and tweak it a little bit. Replace the code in random.html.erb with this:

<div class="rounded overflow-hidden shadow-lg">
  <div class="px-6 py-8 h-full">
    <div class="font-bold text-xl mb-2"><%= idea.description %></div>
    <p class="text-sm text-gray-700"><%= idea.author %></p>
    <div class="mt-4">
      <%= link_to 'Delete', idea_path(idea), method: :delete, class: 'text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-red-600 dark:hover:bg-red-700 focus:outline-none dark:focus:ring-red-800', data: {confirm: "Are you sure?"} %>
      <%= link_to 'Revise', edit_idea_path(idea), class: 'text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800' %>
    </div>
  </div>
</div>

If we refresh the page, we see that it's nicely displayed now.

There's one little gotcha for this page though. The page will actually give us an error that the @idea is nil if we don't have any ideas yet. This isn't good and it means that we need to tinker with the code here.

What we can do is use an if else statement and say, if @idea is present, then we display the button and the random idea, otherwise display some message saying there are no ideas.

We can actually do this pretty simply in our views.

<% if @idea.present? %>
  <h1 class='mb-5 text-2xl font-bold'>Inspire Me</h1>

  <div class="rounded overflow-hidden shadow-lg">
    <div class="px-6 py-8 h-full">
      <div class="font-bold text-xl mb-2"><%= idea.description %></div>
      <p class="text-sm text-gray-700"><%= idea.author %></p>
      <div class="mt-4">
        <%= link_to 'Delete', idea_path(idea), method: :delete, class: 'text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-red-600 dark:hover:bg-red-700 focus:outline-none dark:focus:ring-red-800', data: {confirm: "Are you sure?"} %>
        <%= link_to 'Revise', edit_idea_path(idea), class: 'text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800' %>
      </div>
    </div>
  </div>
<% end %>

Conditionals in the Views

We've talked about how we can use <%= %> and <% %> to embed ruby code into our erb files.

In the code above, we used an if statement in the erb file. This is just another example of ruby being used inside the erb file. It works just like ruby, if a condition is true, the HTML code inside of the block is displayed, otherwise, it is not.

Sweet, you've now added all of the pages successfully! The final step in this lesson is to add a link to the random page in the navbar.

Go to application.html.erb in Sublime and above the link to the "About" page, add the "Random" page link. I named my page the "Inspire Me" page, just because it sounds cooler :D

Again, let's try to generate this link yourself. A hint is to look into your rails routes!

If you did it correctly, it should look like this:

<nav class="bg-white border-gray-200">
  <div class="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-1 md:p-4">
    <a href="/" class="flex items-center space-x-3 rtl:space-x-reverse">
      <span class="self-center text-2xl font-semibold whitespace-nowrap font-pacifico text-[30px] tracking-[2px] text-primary-500">Ideator</span>
    </a>
    <button data-collapse-toggle="navbar-default" type="button" class="inline-flex items-center p-2 w-10 h-10 justify-center text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200" aria-controls="navbar-default" aria-expanded="false">
        <span class="sr-only">Open main menu</span>
        <svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 17 14">
            <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h15M1 7h15M1 13h15"/>
        </svg>
    </button>
    <div class="hidden w-full md:block md:w-auto" id="navbar-default">
      <ul class="font-medium flex flex-col p-4 md:p-0 mt-4 border border-gray-100 rounded-lg bg-gray-50 md:flex-row md:space-x-8 rtl:space-x-reverse md:mt-0 md:border-0 md:bg-white">
        <li>
          <a href="#" class="block py-2 px-3 text-white bg-blue-700 rounded md:bg-transparent md:text-blue-700 md:p-0" aria-current="page">All Ideas</a>
        </li>
        <li>
          <a href="/random" class="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0">Inspire Me</a>
        </li>
        <li>
          <a href="/about" class="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0">About</a>
        </li>
      </ul>
    </div>
  </div>
</nav>

Congratulations! You've now officially built a fully functional app! The next few steps will be the final touches to get your app fully in shape :)

Deploying to Heroku

After going through the standard git workflow, let's deploy all of the new changes that we have made to Heroku.

git push heroku master

Every time we push to Heroku, we should run migrations on the production server:

heroku run rails db:migrate

Then we should restart the server:

heroku restart
Lesson list