Table of Contents

View Screencast (Quicktime)
Right-click and choose Save As to save file to your computer


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.


Want to help spread the word? We’d be grateful if you would include a link to the course in your blog, web site, or emails.

Putting the Page Contents into the Database

29 comments

In this lesson, we create our first database table and Rails model.

In the previous lesson, we created static pages, with all the contents in the view files. The problem with this approach is that to change any text, you must modify the code.

A better approach is to put the page contents into the database, so we can then provide an administrative interface that allows non-technical users to modify the pages. In this lesson, we do just that, creating the core of a simple content management system (CMS).

Setup

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

See Lesson 8 for pointers on setting up your development environment.

In Lesson 8, we explained how to set up the MySQL database. In this lesson, we use SQLite, which is a little easier to get going (if you’re using Leopard, you don’t have to do anything to use SQLite). If you want to use MySQL instead, you just need to change the settings in database.yml. In particular, in the development section, replace the code in the sample application with something like this:

  adapter: mysql
  database: learning_rails
  username: root (or other user name)
  password: secretword (whatever your password is; leave blank if none)
  host: localhost

You’ll also need to create the database, using the mysql command-line interface or one of the GUI interfaces (we’re partial to Navicat). With sqlite, this is done for you automatically.

Lesson Outline

Here’s the coding steps we take in this lesson. Watch the screencast for details and explanations (see link at the top of the left column).

1. Delete the four static views in views/pages

2. Create a scaffold for the new Page model with this command:

script/generate scaffold page name:string title:string body:text

3. Run the migration:

rake db:migrate

4. Start the server:

script/server

5. Delete the automatically generated layout file views/layouts/pages.html.erb

6. Create the four pages (home, about, contact, resources) through the admin interface:

Browse to http://localhost:3000/pages/new

7. Create a controller and view for the public view of the page:

script/generate controller viewer show

8. In controllers/viewer_controller.rb, add this line to the show method:

@page = Page.find_by_name(params[:name])

9. Replace the boilerplate text in views/viewer/show.html.erb with this line:

<%= @page.body %>

10. You can now access the home page using the explicit URL:

http://localhost:3000/viewer/show?name=home

11. Create a route to clean this up. Add this line to config/routes.rb, after the map.resources line:

map.view_page ':name', :controller => 'viewer', :action => 'show'

12. Update the route for the root (home) page (we created this line in Lesson 9):

map.root :controller => 'viewer', :action => 'show', :name => 'home'

13. Fix the navigation links in views/layouts/application.html.erb:

<li><%= link_to 'Home', view_page_path('home') %></li>
<li><%= link_to 'Resources', view_page_path('resources') %></li>
<li><%= link_to 'About Us', view_page_path('about') %></li>
<li><%= link_to 'Contact Us', view_page_path('contact') %></li>

14. Change the title tag line so that the title is pulled from the database:

<title><%= @page.title %></title>

This will work for our normal pages, but it won’t work for the admin pages, since there isn’t always a valid @page object for those pages. So we need another way to set the page title for those pages. We change the layout to this:

<title><%= @pagetitle || @page.title %></title>

The || is the Ruby OR operator. If the item before the OR is not false, then the second item is not evaluated, so this expression essential says “use @pagetitle, unless it is nil; if it is nil, then use @page.title”. This enables us to set the pagetitle with an explicit instance variable in the admin controllers, and still use the @page object in the normal page controller.

Now we need to set @pagetitle in the pages_controller. We want to set it to “Page Administration,” regardless of which action is executed. Rather than placing this code in every action, we can use a before filter, which runs the filter action before any other controller action. The code, which goes at the top of pages_controller.rb, is as follows:

before_filter :loadmetadata

def loadmetadata
  @pagetitle = "Page Administration"    
end

Common Problems

Note that the home page route that we set requires that you create a page named home in the database. If you haven’t created a page with this name, you’ll get an error when browsing to the base URL. (To create a page in the database, browse to localhost:3000/pages/new)

Also, the navigation buttons assume there are pages with the names of about, resources, and contact, so if you haven’t created pages with those exact names in the database, you’ll get an error when you click on the corresponding button.

Onward!

We’re back to where we started! The site now works just like the one we created in Lesson 9, but now all the page contents are in the database, and we have a simple administrative interface to edit this text.

There’s one big problem with this simple implementation: anyone who can guess the URLs for accessing our admin interface can modify the site! In the next lesson, we’ll add a user log-in system to provide authentication for accessing the admin interface.

Resources

For more on the SQLite database, see our list of SQLite 3 tutorials, software, and FAQs.

Another Rails 2.0 scaffolding tutorial.

Peepcode has a two-part introduction to Rails, titled Rails From Scratch.

Ready to dive deeper into Rails? See our list of Ruby on Rails books


Add a Comment

Have a comment or question about this lesson? Add it here.






Comments on This Lesson

From: Andreas Lyngstad       Date: 07/05/08 04:04 AM

Subject: Subject: routes.rb

Thanks for comment, Christopher. I will try to do some work on this. It might be in a few days, because the sun is finally shining here in Norway. So, i guess we need to enjoy the outdoor while it lasts. I’ll get back to you on it.

From: Rafael Jamur       Date: 07/03/08 05:17 PM

Subject: Excelent job.

Thanks a lot for this work.

From: Christopher Haupt       Date: 07/03/08 08:08 AM

Subject: RE: routes.rb

Andreas: Good question. There are lots of strategies you could take here. For instance, you could introduce a specific, new “home” action, set that in the routes file to keep it fixed, then put logic in the controller to resolve which page is the “home page”. You might look for the name “home”, or perhaps add to the model so the user can mark any page as the “default” page, or some other even just have a static bit of text that is used if the page named “home” can’t be found.

Try some experiments and let us know what you come up with!

-Christopher

From: Andreas Lyngstad       Date: 07/03/08 03:03 AM

Subject: routes.rb

Hello – I really love these screencasts. They give understanding of the rails structure that no other book or screencast. I have one question though. If you change the name of the first page (home) to something else, you also have to change it in the routes.rb map.root. How can we protect the users from doing this. Is it possible to lock the name on the first page or maybe rout to the id number instead?

From: Rushil       Date: 06/23/08 12:12 PM

Subject: InvalidAuthenticityToken

Hey guys, I’m working on windows, and as far as I know, I was able to setup my environment for Ruby on rails perfectly. While following this lesson, when I get to the point of creating new pages to be added (after generating the scaffold and migrating) , I get the error ActionController::InvalidAuthenticityToken in PagesController#create … when I click on create. I tired googling but to no avail. I’d appreciate if you could help me out….. in case u need more details regarding the error, please let me know.

Thanks a lot! Really njoy ur tutorial!

From: Ben       Date: 06/23/08 04:04 AM

Subject: Problem

Hi,

After doing what you showed and updating the viewer controller I get an “undefined local variable or method” on page. How does the controller recognize the model? I must be doing something wrong.

Thanks

From: Sonali Agrawal       Date: 06/18/08 06:18 PM

Subject: Problem Solved

Hello Michael,

Thank you. There was no typo error. I just noticed that I had an older version of Ruby Gem. I updated to the latest 1.1.1 one, and now it works. Thanks again, and sorry for the stupid question from me!!

From: Michael Slater       Date: 06/18/08 04:16 PM

Subject: MethodNotAllowed error

Sonali, check your routes.rb file. I suspect you have a typo in there. If you can’t spot it, try replacing your file with the one from the end of lesson zip file.

From: Sonali Agrawal       Date: 06/18/08 04:16 PM

Subject: Action Controller: Exception caught error.

I have been following your tutorials from the start. The application was working fine. But all of a sudden after I did the changes, I am getting this error:

ActionController::MethodNotAllowed

Only get, head, post, put, and delete requests are allowed.

What can be the problem? I am not able to move ahead.

From: Walter       Date: 05/14/08 12:12 PM

Subject: action/id for RESTful routes

Thanks Michael. I was seeing lots of information from “rake routes” and didn’t realize it was the default included RESTful behaviour. It makes sense now ;) Cheers.

From: Michael Slater       Date: 05/14/08 11:11 AM

Subject: action/id for RESTful routes

Walter, those routes come from the “map.resources :page” line, which generates a whoe set of RESTful routes for the Page resource. pages/show/4 is the traditional route using the default route definition you mention. pages/4 is the RESTful route, in which the action is inferred from the fact that a get request is being made of the page resource and an id is being provided. A get request with no id triggers the index action; a get request with an id triggers the show action.

From: Walter       Date: 05/13/08 10:22 PM

Subject: question regarding :id association in controller

if the default routes setup is :controller/:action/:id, how does rails know which action is applied in show and edit in the PagesController ie: pages/4/show and pages/4 both work for show, and pages/4/edit and pages/edit/4 for edit. It all works but why can it work both ways?

I see in /pages/index.html.erb that it just iterates the variable page, but it has no action association.

Other than that I’m fine with the tutorials, and am enjoying the series. Keep going!

Cheers

From: Michael Slater       Date: 05/11/08 07:07 AM

Subject: No action error

Paul, it sounds like perhaps you skipped a step. Go back to Steps 10-13 in the lesson notes and make sure you’ve done all those items.

If you’re still getting an error, for what URL does the error occur?

From: Paul Denlinger       Date: 05/11/08 02:02 AM

Subject: Error message after deleting static pages

Hi— First of all, thanks for a great series of lessons. I have a problem. After I deleted the static pages, and the views/layouts/pages.html.erb file, I could not connect and got an error message: “Unknown action, No action responded to home” Can you tell me what’s wrong?

From: Christopher Haupt       Date: 04/27/08 07:19 PM

Subject: RE: Questions about how to forget about links

[Manuel] We’ll be automating the creation of the navigation links (tabs) in a couple of episodes and over time introduce additional refinements for organizing pages.

From: nate       Date: 04/25/08 11:23 PM

Subject: I'm enjoying the course

Hi guys, I’ve been listening to your lessons while also working through the RailsSpace book. It’s great to see different approaches, and I really appreciate the extra effort you put into the abstract concepts, which is sometimes lacking in RailsSpace.

From: manuel       Date: 04/20/08 09:21 PM

Subject: Question about how to forget about the links

Hi, I’ve been following your lessons and I think they are amazing. Thanks for all this information.

Now, I have a question:

Right now, every time I create a new page other than home, resources, etc. (the original ones) I have to go to layouts>application.html.erb to add that new page manually. How can I automatize this, I mean, that, once I create the new page, for instance, “how do we do what we do”, the navigation bar get updated by the application not by hand.

Can you put that in the lesson 11?

Thanks

From: Christopher Haupt       Date: 04/19/08 09:09 AM

Subject: Viewer show action not working solution

[Working with Kenn offline] The find that is used by the viewer controller is case sensitive and uses the page model’s name attribute as a key to locate it. This means that you need to make sure the name you enter in the database (e.g. ‘home’, ‘about’, ‘resources’, and ‘contact’ in this lesson) are all the same case as used in places like the layout code that calls the viewer (see the nav bar code). The name attribute isn’t user visible, it is just a code word for us to use to locate and find a specific page by “name” behind the scenes. A good exercise for you all would be to update the pages and viewer controller to make entry and use of the name attribute always one case or another.

From: Kenn       Date: 04/18/08 12:12 PM

Subject: Can't fiqure this out...

NoMethodError in Viewer#show

Showing viewer/show.html.erb where line #3 raised:

You have a nil object when you didn’t expect it! The error occurred while evaluating nil.body

Extracted source (around line #3):

1: <%= @page.body %>

From: Ljuba       Date: 04/17/08 11:11 AM

Subject: Thanks Christopher

I just watched the updated version of lesson 10. Thanks a lot!

From: Christopher Haupt       Date: 04/16/08 04:16 PM

Subject: Added title fix section to podcast

Per the discussion here, I’ve added a section to the screencast at the end that addresses a fix to the title handling. I’ve also updated the code archive posted here. If you want to rewatch just the updated section, it starts around the 27 minute mark.

From: Robert L. Crocker       Date: 04/16/08 11:11 AM

Subject: Screencast #10

Definitely not a very useful app but great instructional tool. I found myself changing settings in the learningrails.css file just to see what happened. Very instructive. I tried the same thing Ljuba tried in regard to using the pages controller and got the same error. So I think he makes a good point but I’m still a little puzzled why @page(s) doesn’t have the information from the table.

The only thing I can think of is that instance variables don’t exist from controller file to controller file. They just exist between a controller and it’s views.

Will be very instructive to watch you guys fix what is apparently a very minor oversight.

From: Christopher Haupt       Date: 04/15/08 04:16 PM

Subject: Fix for layout

...and if you want a quick fix for the layout issue below, change @page.title in the application.html.erb layout file to this: (@page and @page.title) ? @page.title : ‘Learning Rails Sample Application’

From: Christopher Haupt       Date: 04/15/08 04:16 PM

Subject: RE: error with pages_controller

Good catch. We’ll be “cleaning” up some of these items as we progress through the lessons. There will be later episodes that cover testing too, so I expect us to try to catch a few of these there too. That said, we’ll likely have a few small logic errors, that while I’d like to say they are all “exercises for the viewer”, some are slipups! We’ll address this one.

From: Ljuba       Date: 04/14/08 08:20 PM

Subject: error with the pages_controller

The only problem with the code at the end of this screencast is that that pages_controller doesn’t know about @page and so there’s an error when it tries to set the title of the administrative “pages”. Just fyi.

From: Ljuba       Date: 04/14/08 08:20 PM

Subject: Nice touch

Also, nice touch making the command-line prompt learningrails_10!

From: Chris Madden       Date: 04/14/08 06:18 PM

Subject: Great Job!

After attending your the Rails Quickstart Seminar in Feb, this is exactly what I need to keep going. Thanks again for these screencasts.

From: Ljuba       Date: 04/14/08 12:12 PM

Subject: Wonderful, as usual

Completely agree with JohnLx about the pacing. Also, thanks for fixing the slow-motion effect of lesson 10. The screencast is much clearer now. Thanks again for making these!

From: JohnLx       Date: 04/14/08 08:08 AM

Subject: Excellent Screencasts

Just wanted to comment that your first two screencasts have been excellent. The pacing seems just about right to adequately cover the necessary concepts without belaboring the basics.

Nice job and thanks for providing this service. I’m looking forward to the next lesson.

—John