Dynamic Page Titles in Ruby on Rails
Tags: rails, ruby, tutorial, beginners
Published: 2022-11-29 01:38:37

Adding dynamic page titles to your Rails web application can be a great way to give your page a more professional look. It is actually very easy to change the page title and I'm going to show you how. In this tutorial, I am going to assume that you know how to create a new rails app as well as the basics of using the terminal. 

In this tutorial I am using Rails version 7.0.4 and Ruby version 2.7.4.

I've also added this to a Github repository in case you wanted to clone the code and follow along. 

https://github.com/jfinley6/rails-dynamic-page-title-tutorial

## Scaffolding/Routes/Seeds

After making a new app and navigating into the folder there are several things we need do to do to before we show off our functionality. First we're going to create a scaffold which will generate our controller, model, and views. I've decided to name it Book and give our model a title, author, and pages attributes.

```bash
➜  books git:(main) ✗ rails g scaffold Book title author genre pages:integer 
```

If you've done this correctly, you should see the following output in your terminal.

```zsh
invoke  active_record
      create    db/migrate/20221128223152_create_books.rb
      create    app/models/book.rb
      invoke    test_unit
      create      test/models/book_test.rb
      create      test/fixtures/books.yml
      invoke  resource_route
       route    resources :books
      invoke  scaffold_controller
      create    app/controllers/books_controller.rb
      invoke    erb
      create      app/views/books
      create      app/views/books/index.html.erb
      create      app/views/books/edit.html.erb
      create      app/views/books/show.html.erb
      create      app/views/books/new.html.erb
      create      app/views/books/_form.html.erb
      create      app/views/books/_book.html.erb
      invoke    resource_route
      invoke    test_unit
      create      test/controllers/books_controller_test.rb
      create      test/system/books_test.rb
      invoke    helper
      create      app/helpers/books_helper.rb
      invoke      test_unit
      invoke    jbuilder
      create      app/views/books/index.json.jbuilder
      create      app/views/books/show.json.jbuilder
      create      app/views/books/_book.json.jbuilder
```
Next you're going to want to run your pending migration to create the Books table.

```
➜  books git:(main) ✗ rails db:migrate
== 20221128223152 CreateBooks: migrating ======================================
-- create_table(:books)
   -> 0.0026s
== 20221128223152 CreateBooks: migrated (0.0026s) =============================
```

Once this is done, we're going to want to create some books for our views as well as change the index page for our website. 
First go to your config > routes.rb file and make sure it looks like the routes.rb file below. This is going to tell Rails which route we should take when the URL ends in "/". In this case, our home page will render the app > views > books > index.html.erb file.
Secondly we can edit our db > seeds.rb file with a couple books to populate our page.

```ruby
#routes.rb
Rails.application.routes.draw do
  root "books#index"

  resources :books
end

#seeds.rb
Book.create(title: "Fellowship of the Ring", author: "J.R.R. Tolkien", genre: "Fantasy/Adventure", pages: 423)
Book.create(title: "Heir to the Empire", author: "Timothy Zahn", genre: "Science Fiction", pages: 528)
Book.create(title: "Mistborn: The Final Empire", author: "Brandon Sanderson", genre: "Fantasy", pages: 672)
```
##Views
Now that we've got our routes setup, we can take a look at our views. We'll be looking at two files, app > views > books > index.html.erb and show.html.erb. I've modified the styling slightly and removed the delete, edit and new book links for simplicity. The code below is exactly what I have in each respective view. 

```erb
<%# index.html.erb %>
<p style="color: green"><%= notice %></p>

<h2 style="text-align: center">All Books</h2>

<div id="books" style="display: flex; flex-direction: column; align-items: center">
  <% @books.each do |book| %>
    <div style="border-style: solid; width: 300px; text-align: center; margin-bottom: 5px">
      <%= render book %>
    <p>
      <%= link_to "Show this book", book %>
    </p>
    </div>
  <% end %>
</div>

 <%#= show.html.erb %>
<p style="color: green"><%= notice %></p>

<div style="display: flex; flex-direction: column; align-items: center">
  <%= render @book %>
  <%= link_to "Back to books", books_path, style: "text-align: left" %>
</div>
``` 

We also want to go to app > views > layouts > application.html.erb and replace the contents of our title tag with the following code. The yield keyword identifies a section where content from the view should be inserted. We can give it a symbol name and now the page title will display to whatever value :title is assigned.

```erb
<%= yield :title %>
```

Now we can go into our show.html.erb and add the following at the top of the file. content_for is how you specify which content is going to be rendered into which content area. In this case, we are assigning a value to :title.

```erb
<% content_for :title do %>
  <%= @book.title %>
<% end %>
``` 

Now, depending on which "Show this book" you click, it will display the name of the book in the browser tab. You can also add this to index.html.erb or any other view where you want the page title to reflect the content on the page.

##Adding a Helper Method

We can also simplify this by adding a helper method. I've added the following to app > helpers > books_helper.rb

```ruby
module BooksHelper

    def title(title)
        content_for :title, title
    end

end
```

Now we can replace our previous content_for code in show.html.erb. 

```erb
<%= title @book.title  %>
```
This will call the title helper method and achieve the same thing we had before. This allows us to reuse the same code over and over and reduce the amount of code that we need.

##Conclusion
Using yield and content_for is a great way to have dynamic page titles. Depending on which view we are rendering, we can change what content is being rendered which is great for our page title. Now we can give unique page titles for all our views and give our website an added professional feel. If you have any questions about I'd be happy to try my and answer!