- XML Reference Guide
- Overview
- What Is XML?
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Table of Contents
- The Document Object Model
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- DOM and Java
- Informit Articles and Sample Chapters
- Books and e-Books
- Implementations
- DOM and JavaScript
- Using a Repeater
- Repeaters and XML
- Repeater Resources
- DOM and .NET
- Informit Articles and Sample Chapters
- Books and e-Books
- Documentation and Downloads
- DOM and C++
- DOM and C++ Resources
- DOM and Perl
- DOM and Perl Resources
- DOM and PHP
- DOM and PHP Resources
- DOM Level 3
- DOM Level 3 Core
- DOM Level 3 Load and Save
- DOM Level 3 XPath
- DOM Level 3 Validation
- Informit Articles and Sample Chapters
- Books and e-Books
- Documentation and Implementations
- The Simple API for XML (SAX)
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- SAX and Java
- Informit Articles and Sample Chapters
- Books and e-Books
- SAX and .NET
- Informit Articles and Sample Chapters
- SAX and Perl
- SAX and Perl Resources
- SAX and PHP
- SAX and PHP Resources
- Validation
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Document Type Definitions (DTDs)
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XML Schemas
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- RELAX NG
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Schematron
- Official Documentation and Implementations
- Validation in Applications
- Informit Articles and Sample Chapters
- Books and e-Books
- XSL Transformations (XSLT)
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XSLT in Java
- Java in XSLT Resources
- XSLT and RSS in .NET
- XSLT and RSS in .NET Resources
- XSL-FO
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XPath
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XML Base
- Informit Articles and Sample Chapters
- Official Documentation
- XHTML
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XHTML 2.0
- Documentation
- Cascading Style Sheets
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XUL
- XUL References
- XML Events
- XML Events Resources
- XML Data Binding
- Informit Articles and Sample Chapters
- Books and e-Books
- Specifications
- Implementations
- XML and Databases
- Informit Articles and Sample Chapters
- Books and e-Books
- Online Resources
- Official Documentation
- SQL Server and FOR XML
- Informit Articles and Sample Chapters
- Books and e-Books
- Documentation and Implementations
- Service Oriented Architecture
- Web Services
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Creating a Perl Web Service Client
- SOAP::Lite
- Amazon Web Services
- Creating the Movable Type Plug-in
- Perl, Amazon, and Movable Type Resources
- Apache Axis2
- REST
- REST Resources
- SOAP
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- SOAP and Java
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- WSDL
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- UDDI
- UDDI Resources
- XML-RPC
- XML-RPC in PHP
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Ajax
- Asynchronous Javascript
- Client-side XSLT
- SAJAX and PHP
- Ajax Resources
- JSON
- Ruby on Rails
- Creating Objects
- Ruby Basics: Arrays and Other Sundry Bits
- Ruby Basics: Iterators and Persistence
- Starting on the Rails
- Rails and Databases
- Rails: Ajax and Partials
- Rails Resources
- Web Services Security
- Web Services Security Resources
- SAML
- Informit Articles and Sample Chapters
- Books and e-Books
- Specification and Implementation
- XML Digital Signatures
- XML Digital Signatures Resources
- XML Key Management Services
- Resources for XML Key Management Services
- Internationalization
- Resources
- Grid Computing
- Grid Resources
- Web Services Resource Framework
- Web Services Resource Framework Resources
- WS-Addressing
- WS-Addressing Resources
- WS-Notifications
- New Languages: XML in Use
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Google Web Toolkit
- GWT Basic Interactivity
- Google Sitemaps
- Google Sitemaps Resources
- Accessibility
- Web Accessibility
- XML Accessibility
- Accessibility Resources
- The Semantic Web
- Defining a New Ontology
- OWL: Web Ontology Language
- Semantic Web Resources
- Google Base
- Microformats
- StructuredBlogging
- Live Clipboard
- WML
- XHTML-MP
- WML Resources
- Google Web Services
- Google Web Services API
- Google Web Services Resources
- The Yahoo! Web Services Interface
- Yahoo! Web Services and PHP
- Yahoo! Web Services Resources
- eBay REST API
- WordML
- WordML Part 2: Lists
- WordML Part 3: Tables
- WordML Resources
- DocBook
- Articles
- Books and e-Books
- Official Documentation and Implementations
- XML Query
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XForms
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Resource Description Framework (RDF)
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Topic Maps
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation, Implementations, and Other Resources
- Rich Site Summary (RSS)
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Simple Sharing Extensions (SSE)
- Atom
- Podcasting
- Podcasting Resources
- Scalable Vector Graphics (SVG)
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- OPML
- OPML Resources
- Summary
- Projects
- JavaScript TimeTracker: JSON and PHP
- The Javascript Timetracker
- Refactoring to Javascript Objects
- Creating the Yahoo! Widget
- Web Mashup
- Google Maps
- Indeed Mashup
- Mashup Part 3: Putting It All Together
- Additional Resources
- Frequently Asked Questions About XML
- What's XML, and why should I use it?
- What's a well-formed document?
- What's the difference between XML and HTML?
- What's the difference between HTML and XHTML?
- Can I use XML in a browser?
- Should I use elements or attributes for my document?
- What's a namespace?
- Where can I get an XML parser?
- What's the difference between a well-formed document and a valid document?
- What's a validating parser?
- Should I use DOM or SAX for my application?
- How can I stop a SAX parser before it has parsed the entire document?
- 2005 Predictions
- 2006 Predictions
- Nick's Book Picks
Now you have the general idea of how to use Ruby, so we can start talking about Rails. We'll create an application an administrator can use to add and edit questions and their answers. Later, we'll put together the ability for users to answer questions online.
We already created the overall framework of the application in the beginning of this
section,
so at this point you should have Rails installed, and you should have created a Rails application called
Surveysays
. You should also have created a database and added one table called
surveys
, as well as modifying the Rails application to access the database.
If you haven't done any of that, now's the time.
If you have done all of that, start by opening a connection to mySQL and adding tables for the questions and answers. For completeness, here is the entire SQL file:
Create database surveysays; Create table surveys ( `id` INT NOT NULL AUTO_INCREMENT , `title` VARCHAR( 100 ) NOT NULL , PRIMARY KEY ( `id` ) ); Create table questions ( `id` INT NOT NULL AUTO_INCREMENT , `surveyId` INT NOT NULL, `questionText` VARCHAR( 100 ) NOT NULL , PRIMARY KEY ( `id` ) ); Create table answers ( `id` INT NOT NULL AUTO_INCREMENT , `questionId` INT NOT NULL, `answerText` VARCHAR( 100 ) NOT NULL , `responses` INT NOT NULL, PRIMARY KEY ( `id` ) );
Okay, now you're ready to start creating pages for editing the questions.
Models, and Views, and Controllers, oh my!
I promised you back in part one that when we got to this point I would talk about the Model-View-Controller structure that is used by Rails, and here we are.
The Model-View-Controller pattern, or MVC, is a way of separating out what you're doing based on function. It consists, as you can tell, of three parts:
- The Model: This is the actual structure of the object your dealing with, or rather the representation of it. For example, at least for the moment we're storing the questions in the database, so you can think of that database table and its columns and its structure as the "model" for a question.
- The View: This is the way in which the object is displayed. For example, if you created an HTML page that displayed a title for the page, a heading, and the question in bold text, that would be a view of the data.
- The Controller: This is the glue that holds together the Model and the View. The Controller determines what should happen when you ask for a list of items, when you try to edit something, or when you try to perform other actions. This is where the logic goes.
Rails has some of its greatest strengths in the fact that this MVC structure is ingrained into it.
What's more, you can automatically generate the code necessary for much of what you need to do.
For example, we'll start by generating the code for the Question
model and
controller. In a command prompt window, navigate to the surveysays
directory
and execute the following commands:
C:\Inetpub\Surveysays>ruby script\generate model Question exists app/models/ exists test/unit/ exists test/fixtures/ create app/models/question.rb create test/unit/question_test.rb create test/fixtures/questions.yml C:\Inetpub\Surveysays>ruby script\generate controller question exists app/controllers/ exists app/helpers/ create app/views/question exists test/functional/ create app/controllers/question_controller.rb create test/functional/question_controller_test.rb create app/helpers/question_helper.rb
Notice that we do have a bit of naming convention here. We are dealing with questions,
so the model is called Question
, singular and uppercase. The controller, on the other hand,
is called question
. Remember that Rails is based on the concept of simplicity; if you
stick to this naming convention, you'll save yourself a lot of trouble because Rails will be able to find things
more easily.
Now, before we move on, I want you to notice that at no time in this discussion have I referenced the class files we've been creating. In fact, while we may poach a method or two, we're not going to use them at all. Part of Rails' advantage is that we don't have to define things twenty-seven times. We defined the database structure and told Rails where it was; that's all we need to do to make things happen.
Let's see all of this in action.
Open your browser and point it to:
http://localhost:3000/question/
Because we haven't actually defined anything for the application to do yet, we'll get a page, but with an error:
Because we provided just a raw object, like most web servers Rails was looking for an "index". Let's
provide one. Open the question_controller.rb
file and add the following:
class QuestionController < ApplicationController model :question def index render_text "Index for the 'question' page." end end
First, we're explicitly associating the Question
model
with this controller using the :question
symbol. From there,
we are creating an action -- just as we did with the objects themselves --
and giving it a single statement, render_text
.
Now if you refresh the browser, you'll find that it calls the index
action:
That looks fine, but if you go behind the scenes and do a "view source" on this page, you'll find that the entire page consists of:
Index for the 'question' page.
That's not very good web programming, putting text out there without so much as an html
tag.
Besides, the whole point of this Model-View-Controller thing is to keep the "view" part out of the "controller" part.
So let's create a view.
In this case we're looking for an "index" view, so create a new page called index.rhtml
(note the "r" in the extension) and save it to the app/views/question
directory. Add the following
code:
<html> <head> <title>Questions, questions questions</title> </head> <body> <h1>The question page</h1> </body> </html>
Now change the controller to remove the render_text
command:
class QuestionController < ApplicationController model :question def index end end
(We can actually remove the method altogether, but leave it for completeness.)
Now if you refresh the page, you'll see the HTML:
Let's play with this for a moment. Remember the scaffold? What if we add it like this:
class QuestionController < ApplicationController model :question scaffold :question def index end end
If you reload the browser, you'll notice that nothing changes. Now do this:
class QuestionController < ApplicationController model :question def index end scaffold :question end
Reload again and notice that it's the last index page that takes precedence, as the browser displays the scaffolding:
Click "New question" and add one or two questions so we have something to work with on our listing page. Later, we'll look at handling this task without the scaffolding.
Now move the scaffold back to its position before the index
action so we can work from our own index.
Making a list, checking it twice
OK, now we're ready to move on to working with the actual data. The simplest thing we can do with
it is to list what we've got, so we want to deal with the list
view. Create a new file,
app/views/question/list.rhtml
, and add the following:
<html> <head> <title>Questions, questions questions</title> </head> <body> <h2>Existing questions</h2> </body> </html>
Point your browser to http://localhost:3000/question/list
-- or just refresh, if you are fresh
off adding questions using the scaffolding -- and you'll see that Rails automatically used the list
view because that's what we asked for in the URL:
But what we really want is the list of questions, so add the following code to list.rhtml
:
<html> <head> <title>Questions, questions questions</title> </head> <body> <h2>Existing questions</h2> <% @questions.each do |@thisQuestion| %> <%= @thisQuestion.questionText %> <br /> <% end %> </body> </html>
Before we go into the actual code, notice that Rails is like many other web programming environments, such as PHP, ASP, and JSP; you can add commands (using <% %>) and output data (using <%= %>) using special tagging.
As for the code itself, it's much like we saw in the actual Ruby application, with an each
iterator that loops through each item in the @questions
array and outputs an attribute of
the item, questionText
. But if we run this code by refreshing the page, we see a problem:
When we were just displaying text, we didn't need to do much from the controller, but now we want to display data, but we haven't told the view what data we want to display! To take care of that, add a new method to the controller:
class QuestionController < ApplicationController model :question scaffold :question def index end def list @questions = Question.find_all end end
Here we're defining the array, so that Rails can pass it to the page. The
Question
model has a find_all
action that returns all
of the data that's in the database, and drops it into the @questions
array. Refresh the page to see
the changes:
Wasn't that easy?
Adding links
Displaying data is nice, but sooner or later you're going to want to do something. Let's start by creating a link to something you can do.
In this structure, anything you'd want to do is called an "action", and each action is defined as a method for the controller. For example, I could create a method like this:
... def list @questions = Question.find_all end def showItToMe render_text "it" end end
and if I visited the URL
http://localhost:3000/question/showItToMe
It'd get a page that looks like this:
Now that's pretty silly, of course, but I'm just pointing out the structure of the URL.
The host and port point to the surveysays
application, the question
is
the object we're dealing with, and the action is showItToMe
. If we were referencing a
specific question, such as one with an id
of 42, the URL would be:
http://localhost:3000/question/showItToMe/42
OK, so that said, let's do something useful. In the list.rhtml
file, tell Rails
to create a link:
<html> <head> <title>Questions, questions questions</title> </head> <body> <h2>Existing questions</h2> <% @questions.each do |@thisQuestion| %> <%= @thisQuestion.questionText %> ( <%= link_to("Change", :action => "edit", :id => @thisQuestion.id) %> ) <br /> <% end %> </body> </html>
The link_to
function creates HTML to link the text Change
to a URL
that points to the edit
action for the question
that corresponds to an
id
of @thisQuestion.id
. If we reload the page, we can see it in
action:
So clicking the first link takes us to:
http://localhost:3000/question/edit/12
because that happens to be question number 12 in the database.
Of course, we haven't actually defined an edit
action, but if you click the link,
you'll see that we go to the edit
action created by the scaffolding:
That's rather the point of the scaffolding; if you want to create your own action, you can, otherwise, the scaffold fills in where necessary.
Of course, this isn't an ideal situation for editing this data. For one thing, the id
value shouldn't be editable. So next, we'll look at interacting with the database directly, so we can
control these things.