Index of All Lessons

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.


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

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: John       Date: 05/17/09 07:55 PM

Subject: Up to date...

Thanks for the great tuts. I just wanted to share a fix I just discovered regarding the scaffolding command. I’m running ruby 1.8.6 and rails 2.3.2. The scaffolding command line shown above was not working for me (<1 for 2> error), and I found some information about how the newer version of rails handles scaffolding differently. In the end however, all I had to do to get the line to run was to change “page” to “Page” in the scaffold command line.

From: Rafa       Date: 03/13/09 10:54 AM

Subject: Thank's from lesson 10

I have just finished this lesson succesfully.

Thank’s a lot.

From: Matt Fox       Date: 12/20/08 01:07 AM

Subject: Thank you

Thank you so much for making these lessons. I have been working on understanding web development for a year now using RoR and your series has taught me more than any book or lesson I have found. Thanks again.

From: Ahad Bokhari       Date: 12/17/08 05:37 AM

Subject: SQL works

In lieu to my sqlite3 problem BELOW SQL however works (I am also using NaviCat) for my GUI. Guess ill go with SQL till i solve the small issue. Cheers

From: Ahad Bokhari       Date: 12/17/08 05:26 AM

Subject: SQLITE3 Problems

When i create an new app Rails doesn’t create a corresponding development.sqlite3 file in the db folder. I have tried to install the sqlite3 gem but it doesnt work. I have tried to update the installed gems → there is nothing to update.

I have even dropped the sqlite application file and sqlite3.dll file into my D:/ruby/bin folder → yet still errors.

Anyone out there facing the same problems?

From: Michael Slater       Date: 11/10/08 08:35 AM

Subject: mysql vs. sqlite problems

Fidelio,

Starting with Rails 2, Rails apps are configured by default to use sqlite. To use MySQL instead, you just need to change the settings in config/database.yml.

In each of the sections (development, test, production) change the code to something like this:


adapter: mysql
database: learningrails_development
username: deploy
password: secret
host: localhost

Substitute, of course, the name of the database you are using, as well as the username and password you have set up for MySQL.

There’s a little more on this in Lesson 22

From: Fidelio Artur       Date: 11/10/08 01:21 AM

Subject: migration

Hi to the team. Thanks for your work. Is pretty helpful. When I run the migration comnand it say

rake aborted no such command file to load – sqlite3 see full trace by running task with —trace.

I am working on mysql 5.0. Isn’t mysql suitable for rails 2.0? What can I do to make this feature operational. Salutation Artur

From: Fidelio Artur       Date: 11/09/08 12:05 PM

Subject: migration

Hello when try the command reke db:migrate the result is: C:\Documents and Settings\SJPB\Desktop\admnstr\fil>rake db:migrate (in C:/Documents and Settings/SJPB/Desktop/admnstr/fil) rake aborted! no such file to load — sqlite3 (See full trace by running task with —trace) C:\Documents and Settings\SJPB\Desktop\admnstr\fil>

what can I do

From: Andreas Lyngstad       Date: 10/27/08 05:06 AM

Subject: map.root

Hello

My approach

map.root :controller => ‘public’, :action => “index”, :name => Page.find(:first).name

is not good. It makes migrate on a empty database impossible. During the migration, routes.rb runs for some strange reason. When it does not find anything it returns an error.

@Micael Slater I do not think it is a good idea to do any finds in the routes.rb file

I think we’ll have to find a better solution for the routing of the main page.

From: Michael Slater       Date: 10/22/08 06:46 AM

Subject: Error no viewer controller

Jaime, have you run the migrations (rake db:migrate)?

If so, make sure your code matches what’s in the archive linked earlier in this article.

From: Jaime       Date: 10/22/08 01:40 AM

Subject: ERROR NO VIEWER CONTROLLER??

Hello..

AFTER all set in the controller viewer, when running the test on firefox web browser, localhost:3000/viewer/show?name=home, it gives me undefined method `find_by_name’ for #….. and also /usr/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:1618:in `method_missing’ app/controllers/viewer_controller.rb:3:in `show’…

I’m running ubunto 8.04TLS and all update version ex: ruby gem 1.3.0..

From: Michael Slater       Date: 10/15/08 10:03 PM

Subject: Finding the home page

Andreas,

Your approach seems reasonable to me. The only downside is that the root page will always be the one with the lowest-numbered database ID, which might not always be what you want if you’ve changed things around.

The best approach would be to add an attribute to the page model for “home”, and find the page that has this attribute set.

From: Andreas Lyngstad        Date: 10/15/08 02:28 AM

Subject: routes.rb

Hello Well,

I guess the sun has been shining for quite a while here. But, now at last I have a possible solution. The problem was that if the root is like this:

map.root :controller => ‘public’, :action => “index”, :name => “home”

It wont work if the user changes the name of, or deletes the home page. So, what if we make a find by id and call the name attribute instead. Like this:

map.root :controller => ‘public’, :action => “index”, :name => Page.find(1).name

It will make it possible to change the name, but it is a “no go” if the user deletes the page. So, my solution was this.

map.root :controller => ‘public’, :action => “index”, :name => Page.find(:first).name

Now, we will do a find on the first instance in the database whatever the id or name is and call the name attribute of this instance.

Does anybody see drawbacks with this approach?

Hope it helps someone!

From: Ronen       Date: 09/26/08 03:36 AM

Subject: Steps 11, 12 - Resolved

Found the comment by James and tried what he suggested. - Restarted the mongrel server, but it didn’t resolve the issue. - Checked the version and it was 1.2.0. - I ended up rebooting my virtual machine and it works now.

From: Ronen       Date: 09/25/08 06:05 PM

Subject: Lesson 10 - Steps 11, 12

Thank you very much for this free online course. It’s a great ‘helper’….

I’m getting the following error when I’m browsing to localhost:3000/home

“Only get, head, post, put, and delete requests are allowed”

I copied the entries from your lesson 10 files, and still get the same thing.

The original link from step 10 (http://localhost:3000/viewer/show?name=home) still works.

What am I missing?

From: Ramiz       Date: 08/03/08 11:42 PM

Subject: script/generate scaffold

thank you it works :-)

From: Michael Slater       Date: 08/03/08 11:36 PM

Subject: PagesHelper problem

The error is because in a previous lesson we created the pages controller, and that had the side effect of creating the pages helper. You need to delete that file before running the scaffold command. It’s in app/helpers.

From: Ramiz       Date: 08/03/08 11:28 PM

Subject: script/generate scaffold

in learningrail_10 i get a error and i dont know what to do please help!!!

imac:learningrails_10 Ramiz$ script/generate scaffold page name:string title:string body:text The name ‘PagesHelper’ is either already used in your application or reserved by Ruby on Rails. Please choose an alternative and run this generator again.

From: Rick       Date: 08/02/08 09:21 PM

Subject: remove pages_helper also

When I started with the learningrails_9 project and followed the screencast, I also needed to delete the PagesHelper file in the Helpers directory or else the scaffold script wouldn’t run (gave the error about that PagesHelper existing.) Once I deleted it, the scaffold command worked fine.

From: Michael Slater       Date: 07/26/08 02:53 PM

Subject: Multiple filters

Gurvinder, to answer your questions:

1. Yes, you can have as many before_filter statements as you’d like, and you can list multiple actions on one statement.

2. Yes, some things require restarting the server, even in development mode, although most do not. I don’t have a crisp definition of what requires a restart — can anyone help out with this?

From: James       Date: 07/19/08 11:49 PM

Subject: Error: ActionController::MethodNotAllowed

Error: ActionController::MethodNotAllowed – Only get, head, post, put, and delete requests are allowed.

Resolved by restarting the mongrel server. I had Rails 2.1 and Mongrel 1.1.4. Use CTRL+C to kill the running server and then restart it with the “ruby script/server” command. I also updated Mongrel to the latest 1.1.5 by performing “sudo gem update mongrel” or just “gem update mongrel” on Windows.

When in doubt, first try restarting the mongrel, passenger, webrick, glassfish server depending on which you are running in development. You are not supposed to have to do this very often during development but sometimes you have to restart the server. i.e. editing the database.yml file or adding a controller, etc. may require a restart of the server.

From: Gurvinder       Date: 07/19/08 03:26 PM

Subject: Couple of Issues

Hi Guys

I like your Screen cast, but while i was working along with your screencast i found couple of issues which are not still cleared like:

1. Can we have multiple befor_filters? 2. When i used the command map.view_page in route.rb it did NOT work till the time i restarted the server….why i have to restart the server?

Waiting for your reply….

From: Yukti       Date: 07/13/08 10:12 PM

Subject: Problem accessing these screen casts

Hi Micheal & Christopher

Hope you are doing good. I am Yukti and am following your tutorials to learn ROR. This is a Bible for me.Thanks a ton !! for the efforts that you both are putting. :)) Till chapter 8 it was all good for me but after that I am just not able to access the tutorials. Reason being the heavy screen casts . Please do something about this. Also if managing screen casts is that difficult, please arrange transcripts or screen shots . Also we can try with flv players.

Will be a great help

Care Yukti.Vig

From: Andreas Lyngstad       Date: 07/04/08 09:41 PM

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 10:43 AM

Subject: Excelent job.

Thanks a lot for this work.

From: Christopher Haupt       Date: 07/03/08 01:12 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/02/08 08:24 PM

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 05:24 AM

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/22/08 09:05 PM

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 11:02 AM

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 09:52 AM

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 09:10 AM

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 05:57 AM

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 04:02 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 03: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 12:53 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/10/08 07:48 PM

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 12:42 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 04:01 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 02:59 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&gt;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 02:12 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 05:42 AM

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 04:45 AM

Subject: Thanks Christopher

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

From: Christopher Haupt       Date: 04/16/08 09:54 AM

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 04:50 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 09:20 AM

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 09:14 AM

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 01:06 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 01:00 PM

Subject: Nice touch

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

From: Chris Madden       Date: 04/14/08 11:58 AM

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 05:54 AM

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 01:34 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

 

Sponsored By

New Relic Rails Performance Monitoring