Table of Contents

View Screencast (Quicktime)

Right-click on the button above and choose Save As to save file to your computer


Support the Course

There's no charge for the course, but we greatly appreciate any donations.

Suggested donations:
  • One or two lessons: $5
  • Several lessons $10
  • Entire course: $25 – $50

We hope you've found the course to be valuable, and we appreciate any support you care to provide.


Sign Up Now!

If you aren’t already receiving our course lessons via email, sign up now to be sure you don’t miss anything.

Every few days, we’ll send you an email with a link to the next episode, plus a list of additional resources for advancing your knowledge.

There’s no cost and no obligation. And we’ll never share your email address with any third party.

We’ll send you the first lesson right away.

Looking for a Powerful Hosted CMS?

The authors of the Learning Rails course also offer a very powerful hosted content management system for web designers, which enables you to build sophisticated, database-driven sites without programming. This is a great alternative to building a custom Ruby on Rails site for those applications for which you just can't justify the cost of a custom solution.

To learn more, sign up for the free Learning Webvanta course on building database-driven web sites without programming.

Lesson 16
Clean-Up

comments Bookmark and Share

Goals

In this lesson we’re taking a break from adding features to do a little cleanup:

  • Get the page title logic out of the application layout
  • Add page titles for admin and login pages
  • Make navigation buttons indicate which is the current page
  • Add a ‘back to previous’ navigation link on subpages
  • Add a little styling to subnav links
  • Set the focus for the login field

Please note that, while we’ve tried to make these notes complete, they aren’t the full tutorial; that’s in the screencast, which you can access via the link on the left.

Setup

We begin with the code with which we ended Lesson 15. These zip files contain the beginning and ending states of the code:

Fix up Page Title Handling

Several lessons ago, as we were building the core of our content management system, we put a quick hack in the application layout (views/layouts/application.html.erb) that put this logic in the wrong place; we want to keep logic out of our views as much as practical. So let’s replace this line:

<title><%= @pagetitle || (@page && @page.title) || 'Learning Rails Sample Application' %></title>

with the much simpler:

<title><%= @pagetitle %></title>

Now we need to set this instance variable appropriately for each view. First, in the viewer_controller show method, insert the line (after @page is set):

@pagetitle = @page.title

That takes care of all pages that come from the content management system. Now we need to take care of the admin and login pages. Add to users_controller:

before_filter :set_pagetitle

def set_pagetitle
  @pagetitle = 'User Administration'
end

This before filter will run before every action, so the page title will be set (to the same thing) for all of them.

In page controller, we already made a very similar addition in a previous lesson, but we called it set_metadata, so for consistency we’ll rename it to set_pagetitle

Finally, the sessions controller needs some attention. Add to the (empty) new action in sessions_controller:

@pagetitle = 'Please Log In'

And after the else in the sessions_controller’s create method:

@pagetitle = "Login was not successful"

You could do more to customize page titles for the various admin pages, but this is enough for us.

Highlight Current Nav Button

Next problem: make the appropriate nav button highlight to indicate the current page.

First, we need to identify which nav button to highlight by using some Ruby code to conditionally insert an ID. We’ll insert the following code in the application layout, in the <li> tag that begins each nav button:

<li <%= "id = 'current'" if @page && @page == page %>>

Now we need a CSS rule, in public/stylesheets/learningrails.css, to style the button for the current page:

#navbar #current a {
    background-color: #000; 
}

Now the navigation button for the current page is highlighted.

Provide a Link Back to Parent Page

When we added subpages in the previous lesson, we didn’t provide any indication when you’re on a subpage as to what the parent page is. There’s several things we might do about this; here’s two possibilities:

We could use the subnav div area to show a “Return to About Us” link, for example, on subpages of About Us. To do so, replace the code at the top of views/viewer/show.html.erb with the following:

<% if !@subpages.empty? %>
  <div id='subnav'>
    <ul>
      <% for page in @subpages %>
        <li><%= link_to page.navlabel, view_page_path(page.name) %></li>
      <% end %>
  </div>
<% elsif @page.parent %>
  <div id='subnav'>
    <ul>
      <li><%= link_to "Return to #{@page.parent.navlabel}",
              view_page_path(@page.parent.name) %>
      </li>
    </ul>
  </div>
<% end %>

If there are subpages, then this code displays the subpage nav. If not, then if there is a parent page, it displays a link back to the parent page. (Note that you’d want to do something a little different if you had multiple levels of subpages.)

Now the subpages of About Us show the link back.

Add a Little Style

The subnav lists are pretty ugly, so let’s style them a little to make them look like buttons. Add the following to public/styles/learningrails.css:

#subnav {
	width: 160px;
	float: left;
	margin: 0 20px 50px -10px;
}
#subnav ul {
    list-style: none;
    font-weight: bold;
    font-size: 13px;
	margin: 0;
	padding: 0;
}
#subnav ul li {
	background-color: #999;
	border-bottom: 1px solid #333;
	border-top: 1px solid #333;
}
#subnav ul li a {
	padding: 5px 10px;
	display:block;
	color:white;
	text-decoration: none;
}
#subnav ul li a:hover {
    background-color: #333;
    color: #fff;
}

Retain Parent Button Highlight On Subpages

Another way we could indicate the parent page would be to keep its navigation button highlighted. We can do this with a small change to the current page id logic in the application layout, adding a test for the parent of the current page:

<li <%= "id = current" if @page && (@page == page or @page.parent == page) %>><%= link_to page.navlabel, view_page_path(page.name) %></li>

Now when you’re viewing one of the subpages of the About Us page, the About Us button is highlighted.

Note that we’ve let some logic creep back into our application controller here, but it is really presentational logic, so it doesn’t feel too bad.

Set Form Field Focus

One last bit of cleanup. On our login page, it’s annoying that you can’t just begin typing; neither of the form fields have focus until you click in one of them. We can fix that by adding a little bit of JavaScript to the bottom of views/sessions/new.html.erb:

<%= javascript_tag "$('login').focus()" %>

And now you can start typing as soon as the login page is displayed.

Moving On

We could go on for several more lessons tuning up our little content management system, but it’s time to move on. Next lesson, we’ll create the resources database and use that to drive the Resources page.


Add Your Comments

(not published)

Reader Comments

20 comments

Just a few tidbits to add here regarding title and DRY concepts

From: Joel Dezenzio, 06/23/09 05:47 AM

Great job on your lessons but I found your @pagetitle to not be very dry when placed against other non-cms type pages in my site. The concept you provided works great for generic controllers and/or the CMS base, but not for additional pages that are non-cms, and especially for one-page MVC content. Repeating the same before_filters and code inside the controller on every controller is a little tedious. I also like to keep my controllers very thin. So, I have done a workaround by implementing the following: In application.html.erb (layout) <%= @pagetitle || yield(:title) %> In application_helper.rb (helpers) def title(page_title) content_for(:title) { page_title } end How you use it is very simple. Go into the view for pages you want specific custom title and place the following at the top of the view: <% title "Your Custom Title" %> For controller groups (say you have 7 different views for one controller) - your scenario with before_filter and @pagetitle works great (as it applies to a group of pages). However, in some of my pages I have single MVC content that displays very advanced tables. On my site I have 32 of them and it just is simpler to use the title helper.

Keep subnav showing

From: Arwed, 01/30/09 02:26 AM

Hi, your lessons are great! Could you please give me a hint, how I can keep showing the subnav when I am in a subpage including how all selected tabs can be highlighted (nav and subnav). Thanks in advance

How to highlight and keep it on the the Log In tab

From: Marcos Ricardo, 10/26/08 06:54 PM

Hi, After finishing this lesson, I realized that the Log In tab is the only that don't remains highlighted when we get the mouse out from it. My question is: How can I fix this ? and if there is a way to do that with no changes at the restful_authentication plugin ? Thanks.

view_page_path(page.name)

From: Ronen, 09/30/08 10:32 AM

Just wanted to mention I was getting my navbar looking like this: /about | /public | /resources I then played around in the application layout file and found that if I removed 'view_page_path' and just left (page.name), my navbar then looks like this: about | public | resources

Small correction

From: Sérgio Silva, 09/15/08 10:40 PM

I guess I suck at putting code in here, so please if you can fix its display do it :P the first line (before def) is a comment. Thanks

Highlight parent page

From: Sergio Silva, 09/15/08 10:37 PM

I've just watched this screencast (well, I've subscribed to your podcasts so I listened to / watched all of the former ones), and even though I've only began studying rails 2 days ago (through your casts, I'd never touched it before and I don't really know anything about web apps :P), but I'd still want to tell you guys something I noticed in this little 'fix'. Thing is, if you ever make subpages of subpages, it won't work because it only reaches current and first parent level. So I made this method that I've put in the Helpers/application_helper.rb (hopefully the right place for it) [code]#Checks if the given page (argv[1]) or any of its parents matches the check (argv[2]) def check_parents(page, check) if page == check return true end while page.parent if page.parent == check return true end page = page.parent end end [/code] and in my application.html.erb i subbed for [code]

  • > [/code] It'll iterate through all parents until it finds a match, then if it finds a match it'll highlight the correct subnav. As I'm really a n00b in this, I dunno if I did it the right way, but meh, even if it's wrong at least I'll get feedback :P

  • NoMethodError in Sessions#new

    From: Alexander, 07/02/08 01:39 AM

    Hello:

    Thanks for wonderful screen-casts and great tutorials.

    As for this tutorial, I have question. Why do I get an exception error, in fact “You have a nil object when you didn’t expect it!”, after placing the dynamic links from the show.html.erb viewer, into the application.html.erb layer folder? Could this be routing problem?

    Thanks for taking the time to answer my query.

    Alex

    NoMethodError in Sessions#new

    From: Alexander, 07/02/08 01:39 AM

    Hello:

    Thanks for wonderful screen-casts and great tutorials.

    As for this tutorial, I have question. Why do I get an exception error, in fact “You have a nil object when you didn’t expect it!”, after placing the dynamic links from the show.html.erb viewer, into the application.html.erb layer folder? Could this be routing problem?

    Thanks for taking the time to answer my query.

    Alex

    From: Robert, 06/23/08 12:31 AM

    Thanks Christopher,

    I reinstalled Quicktime as you suggested and all is fine. (I had an older version of Quicktime already on my computer but that didn’t work either. After updating to the latest version all worked well.)

    Now I have some catching up to do!

    Thanks again for your help. Robert

    RE: No Audio on Lessons 15/16 (and probably later)

    From: Christopher Haupt, 06/22/08 01:52 PM

    Glad they are helpful Robert. Perhaps the easiest thing to do would be to install Apple’s free iTunes player (which also installs Quicktime). If you already have it installed, try opening the MOV file in it instead of RealPlayer. That should get you going.

    No Audio on Lessons 15 & 16

    From: Robert, 06/22/08 03:19 AM

    Hi Christopher,

    Thanks for all the work you and Michael have done in putting this course together for us. As a newcomer to Ruby & Rails, yours is a whole new world of potential and opportunity opening before me and know that many of us appreciate the help you are offering us.

    My OS is Windows XP Home. My videos are being played on RealPlayer. It comes up automatically to play your videos and had been working fine until lesson 15. It has been my default player and I have not needed to change it until perhaps now. What should I be using?

    Robert

    RE: No Audio

    From: Christopher Haupt, 06/20/08 05:31 PM

    Robert: Starting around episode 15 we switched around some of our audio encoder settings to get higher quality sounds and better compression. What OS and movie playing software are you using? On Windows and Mac, the latest Quicktimes should work fine. We are using AAC with no protections (no DRM).

    No Audio on Lessons 15 & 16

    From: Robert, 06/20/08 01:34 PM

    Something happened! I was viewing the screencasts fine up thru Lesson 14. Then lesson 15 would view with no audio. I was hoping that 16 would be back to normal, but it too is missing the sound portion. I can go back and play my older downloaded lessons like Lesson #14 and it plays fine.

    If I re-download Lessons 15 & 16, they still have no sound! What happened?!

    Thanks, Robert

    Update: Debugging Solution Found

    From: Walter, 06/05/08 01:57 PM

    Yesterday a user replied at railsforum that in using Restful Authentication, I have to give the attr_accessor the new variables that are accepted. Sure enough, by amending the line in user.rb with 3 new items at the end ie: attr_accessible :login, :email, :password, :password_confirmation, :first_name, :last_name, :exec_position …Worked. whew

    Mental note: whenever data is in doubt, always check the model for authentication new or old behaviours

    Cheers Walter

    Re: Debugging help

    From: Walter, 06/04/08 06:35 AM

    Thanks. Yes, I had restarted the server. Your code does show data being passed, but further along it doesn’t save the data for other views into @user. I’ll try other actions with their results later in the evening.

    - !map:HashWithIndifferentAccess user: !map:HashWithIndifferentAccess password_confirmation: “12345” exec_position: bottle washer first_name: foo last_name: bar login: foobar password: “12345” email: foobar@email.com commit: Sign up authenticity_token: 44597daa797ed198645aeb027e706a00fab4fd4d action: create controller: users

    Debugging help

    From: Michael Slater, 06/04/08 04:53 AM

    Walter, what you’re doing should work. I took a look at your Railsforum post and I don’t immediately see what’s wrong.

    Have you restarted the server since you made the changes? Not sure if you need to, but it never hurts.

    To see what variables are actually reaching the view, add the following at the start of your user/create action:

    render :inline => "<%= debug params %>" and return
    

    Own cleanup not showing up

    From: Walter, 06/04/08 03:56 AM

    see http://railsforum.com/viewtopic.php?id=18937 for details on issue. still can’t add new field data to @user from update action :(

    Own cleanup not showing up

    From: Walter, 06/04/08 12:53 AM

    Hi.

    All I did was add some new columns (first_name, last_name) to the user table via a migration, ran rake db:migrate, and updated the user loop in the edit / show actions to see user.first_name etc.

    However the new data in the fields are not being saved nor are they showing up in new pages. I can run script/console and save new information to an attribute, but outside no.

    I thought that the update action with the @user.update_attributes(params[:user]) in the users_controller.rb was saving this new information?

    Clearly I’ve missed a step, can anyone enlighten?

    TIA Walter

    typo

    From: Kenn, 05/31/08 11:13 AM

    In (Provide Link To The Nav Bar) Section you list [<li <%= "id = 'current'"] and later in (retain parent button) you change it to ["id = current"]

    Highlight Current Nav Button

    From: andres, 05/27/08 04:31 AM

    Firt of all, sorry for my English. i’m from Spain and i have a low level of English.

    Well, my question is: How can i Highlight Current Nav buttom when i'm in a subpages of a subpages?

    example: cars ,old_cars ,old_yellow_cars

    when i’m in “old_yellow_cars”, “cars” is not Highlight no?

    thank you for the help

     

    Sponsored By

    New Relic Rails Performance Monitoring