Stylesheet and Image Assets

Exercises

Objective

Since this isn't a course about web design, we prepared a CSS stylesheet, images, and sample movie data for you. It's always more enjoyable to work on an application that has some style, images, and realistic data. And this gives us an opportunity to learn the basics of how Rails handles assets such as stylesheets and images.

In this exercise we'll copy in the prepared asset files and explore how they're handled. In the end you'll know where to put web design assets in a Rails app, whether you get those assets from a web designer or you apply your own web design skills!

1. Install the Bootstrap Gem

Our design uses the popular Bootstrap framework as the foundation and then adds a some custom CSS on top of that. The bootstrap gem makes it easy to use Bootstrap in Rails, so our first step is to add that gem as a dependency of the flix app.

  1. First, stop your currently-running flix app by typing CTRL-C in the console window where it's running.

  2. Then add the following line to the Gemfile in the flix directory:

    gem 'bootstrap', '~> 4.3.1'
    

    Remember, all Rails apps have a Gemfile that lists all the gems necessary to run the app. It generally doesn't matter where you add gems in the file, though we tend to put them after the primary gems that are listed by default.

  3. Now go back to the console window. You should still be in the flix directory. Install the gem by typing

    bundle install

    You should see output indicating that the bootstrap gem was installed, as well as other gems it depends on.

2. Copy Prepared Files

The next step is to copy the prepared files into the appropriate directories of the flix app. Feel free to do this however is most comfortable to you on your operating system:

  1. First, download the prepared files. When you unzip the file, you'll end up with a directory named pragstudio-rails-prepared-files. Inside that directory you'll see a directory named prepared-files. And inside that directory you'll find a directory named flix.

  2. Copy all the image files contained in the prepared-files/flix/images directory into your flix/app/assets/images directory.

  3. Then copy the prepared-files/flix/custom.scss file into your flix/app/assets/stylesheets directory.

  4. Finally, copy the prepared-files/flix/seeds.rb file into your flix/db directory, overwriting the existing seeds.rb file. Take a peek at this file and you'll see that it uses Movie.create! to create a more comprehensive set of movies with more realistic data.

3. Run the Styled App with Seed Data

With the prepared files copied, let's take the app for a spin:

  1. First, the development database currently has some movies we created from the Rails console in previous exercises. We've included those same movies in the seeds.rb file, as well as some newer movies. So we want to clear out the database and populate it with the data in the seeds.rb file. To do that, use the following command:

    rails db:reset

    That handy command drops and re-creates the development database, applies all the migrations, and runs the db/seeds.rb file which creates example movies in the database.

  2. Then go ahead and fire up the server:

    rails s
  3. Now if you browse to http://localhost:3000/movies the page should have a blue header and a black footer. You'll also see more example movies in the main content of the page.

4. Update the Index Template and Layout File

The header and footer are now styled, but the movie listing isn't yet taking advantage of the CSS styles we copied into the app. We'd also like to display the application's logo image in the header.

  1. First, to apply the styles to the movie listing, paste the following into your app/views/movies/index.html.erb file, replacing what's already in that file:

    <% @movies.each do |movie| %>
      <section class="movie">
        <div class="summary">
          <h2>
            <%= movie.title %>
          </h2>
          <h3>
            <%= total_gross(movie) %>
          </h3>
          <p>
            <%= truncate(movie.description, length: 150, separator: ' ') %>
          </p>
        </div>
      </section>
    <% end %>
    

    Don't worry: All we've done is rearranged things slightly to use different HTML tags with class names that trigger the corresponding CSS rules in our custom.scss stylesheet. We also decided not to display the movie ratings and the year the movie was released on this page, but those attributes will make a comeback when we add the movie detail page in the next section.

  2. Then display the application's logo image in the header.

    Remember, the header is defined in the layout file: app/views/layouts/application.html.erb. Use the image_tag helper to display the image file named "logo" in the header tag in place of the static text.

    <header>
      <%= image_tag("logo") %>
    </header>
    
  3. Now if you refresh the http://localhost:3000/movies page you should see the logo in the upper-left corner and the listed movies should be styled with a border separating each movie. Voila!

How Stylesheets Are Processed

Just to recap how stylesheets get picked up by Rails, open the application.html.erb layout file and narrow in on this line:

<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>

The stylesheet_link_tag helper generates a link tag for the specified stylesheet file. The .css extension is automatically appended. So, in this case, our layout file references a stylesheet named application.css.

Where does that stylesheet file live? Well, whenever you reference an asset — be it a stylesheet, image, or JavaScript file — Rails actually searches for it in the following three directories:

  • app/assets contains assets that are specific to this application

  • lib/assets contains assets for custom libraries that you write and share across your Rails apps

  • vendor/assets contains third-party assets that are used by this application such as an open-source lightbox or calendaring library

Since application.css is a stylesheet that's specific to this app (hence the name), it lives in the app/assets/stylesheets directory.

Open the application.css file and you should see one big CSS comment that looks something like this (don't worry about the ordering of the lines):

/*
 * This is a manifest file...
 *
 *= require_tree .
 *= require_self
 */

If you've ever laid eyes on a CSS file, you'll quickly notice that this doesn't look like your run-of-the-mill stylesheet. It's actually a valid CSS file, but all the lines are in CSS comments. Embedded in those comments are special directives that start with an equal sign (=). Rails uses these directives to figure out which stylesheet files should be automatically included when the application.css file is requested.

The default application.css has two directives, which is all you really need:

*= require_tree .

The require_tree directive includes all files in the specified directory and any subdirectories. Using a dot (.) as the directory name means the "current directory", so all CSS files in the app/assets/stylesheets directory (and any subdirectories) will be included.

*= require_self

The require_self directive simply includes the contents of the current file (application.css). So if we had any CSS below the comments, it would get included.

So the application.css file is really just a manifest: a list of other files to include in the final application.css file. So you can drop stylesheet files in the app/assets/stylesheets directory and the require_tree directive will make sure they're included. The benefit of this approach is that we can organize styles into different stylesheets, in much the same way we strive to organize our source code into separate files.

It's worth noting that Rails supports Sass out-of-the-box and it's the default pre-processor for files with the .scss extenion. So our custom.scss file will get automatically pre-processed by Sass to generate valid CSS. But you can always use straight CSS if you prefer.

Solution

The full solution for this exercise is in the assets directory of the code bundle.

Bonus Round

If you have some favorite movies that aren't in the movie listing, feel free to add them to the db/seeds.rb file. Then to reseed the data, run

rails db:reset

Wrap Up

It's fun playing around with colors, fonts, rounded corners, drop-shadows, and all the other stuff that makes your app light up in the browser. And Rails makes it really easy to get started and keep things organized. So if you have web design chops, by all means go for it!

On the other hand, if web design isn't exactly your strong suit, then here's our recommendation: when it comes to building your own Rails app, now's the time to get a web designer. Web design is a skill, and like any skill it can take years to master. It's a rare programmer who has invested the time to learn both disciplines well. With what you've just learned about assets, you can meet a designer in the middle. And together you can create an app that works and looks great!

Anyway, at this point the movie listing page is looking pretty good. But given that we've truncated the movie description and removed a couple movie attributes from this page, we need another page that shows a movie's full details. And wouldn't you know it, that's our task for the next section.

But first, it's break time! Stand up. Stretch. Refresh yourself. Then enjoy a little movie-related humor with Men in Black 3 Bloopers or Avengers Gag Reel.

Dive Deeper

Web design is an entire course in itself. If you're new to HTML and CSS, check out the following resources:

To dive deeper into web design with Rails, check out the following Pragmatic Bookshelf books:

To learn more about the Rails asset pipeline, refer to the Rails Guides: Asset Pipeline