10: Putting the Page Contents into the Database




Learning Rails show

Summary: In this lesson, we create our first database table and Rails model. <p> </p> <p>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.</p> <p>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 (<span class="caps">CMS</span>).</p> <h2>Setup</h2> <p>We begin with the code with which we ended Lesson 9. These zip files contain the beginning and ending states of the code:</p> <ul> <li><a href="/learningrails_9.zip">Learning Rails example app code as of the end of Lesson 9</a></li> <li><a href="/learningrails_10.zip">Learning Rails example app code as of the end of Lesson 10</a></li> </ul> <p>See <a href="/podcasts/79333-setting-up-your-development-environment/">Lesson 8</a> for pointers on setting up your development environment.</p> <p>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:</p> <pre> adapter: mysql database: learning_rails username: root (or other user name) password: secretword (whatever your password is; leave blank if none) host: localhost </pre> <p>You’ll also need to create the database, using the mysql command-line interface or one of the <span class="caps">GUI</span> interfaces (we’re partial to <a href="http://navicat.com">Navicat</a>). With sqlite, this is done for you automatically.</p> <h2>Lesson Outline</h2> <p>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).</p> <h3>1. Delete the four static views in views/pages</h3> <h3>2. Create a scaffold for the new Page model with this command:</h3> <pre> script/generate scaffold page name:string title:string body:text</pre> <h3>3. Run the migration:</h3> <pre> rake db:migrate</pre> <h3>4. Start the server:</h3> <pre> script/server</pre> <h3>5. Delete the automatically generated layout file <code>views/layouts/pages.html.erb</code> </h3> <h3>6. Create the four pages (home, about, contact, resources) through the admin interface:</h3> <pre> Browse to http://localhost:3000/pages/new</pre> <h3>7. Create a controller and view for the public view of the page:</h3> <pre> script/generate controller viewer show</pre> <h3>8. In controllers/viewer_controller.rb, add this line to the show method:</h3> <pre> @page = Page.find_by_name(params[:name])</pre> <h3>9. Replace the boilerplate text in views/viewer/show.html.erb with this line:</h3> <pre> &lt;%= @page.body %&gt;</pre> <h3>10. You can now access the home page using the explicit <span class="caps">URL</span>:</h3> <pre> http://localhost:3000/viewer/show?name=home</pre> <h3>11. Create a route to clean this up. Add this line to config/routes.rb, after the map.resources line:</h3> <pre> map.view_page ':name', :controller =&gt; 'viewer', :action =&gt; 'show'</pre> <h3>12. Update the route for the root (home) page (we created this line in Lesson 9):</h3> <pre> map.root :controller =&gt; 'viewer', :action =&gt; 'show', :name =&gt; 'home'</pre> <h3>13. Fix the navigation links in views/layouts/application.html.erb:</h3> <pre> &lt;li&gt;&lt;%= link_to 'Home', view_page_path('home') %&gt;&lt;/li&gt; &lt;li&gt;&lt;%= link_to 'Resources', view_page_path('resources') %&gt;&lt;/li&gt; &lt;li&gt;&lt;%= link_to 'About Us', view_page_path('about') %&gt;&lt;/li&gt; &lt;li&gt;&lt;%= link_to 'Contact Us', view_page_path('contact') %&gt;&lt;/li&gt; </pre> <h3>14. Change the title tag line so that the title is pulled from the database:</h3> <pre> &lt;title&gt;&lt;%= @page.title %&gt;&lt;/title&gt;</pre> <p>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:</p> <pre> &lt;title&gt;&lt;%= @pagetitle || @page.title %&gt;&lt;/title&gt;</pre> <p>The <code>||</code> 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.</p> <p>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:</p> <pre> before_filter :loadmetadata def loadmetadata @pagetitle = "Page Administration" end </pre> <h2>Common Problems</h2> <p>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 <span class="caps">URL</span>. (To create a page in the database, browse to localhost:3000/pages/new)</p> <p>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.</p> <h2>Onward!</h2> <p>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.</p> <p>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.</p> <h2>Resources</h2> <p>For more on the SQLite database, see our list of <a href="/topic/24373-sqlite">SQLite 3 tutorials, software, and FAQs</a>.</p> <p>Another <a href="http://fairleads.blogspot.com/2007/12/rails-20-and-scaffolding-step-by-step.html">Rails 2.0 scaffolding tutorial</a>.</p> <p><a href="http://peepcode.com">Peepcode</a> has a two-part introduction to Rails, titled <a href="http://peepcode.com/products/rails-from-scratch-part-i">Rails From Scratch</a>.</p> <p>Ready to dive deeper into Rails? See our <a href="/books/list?category=5">list of Ruby on Rails books</a></p>