- 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 that you've seen how fast you can create an application with Rails, it's time to really start getting down to business. Every Rails application is really a Ruby application, so if you're really serious about building one, you'll need to learn Ruby.
Ruby is not a difficult language to learn as long as you're already familiar with object oriented programming concepts. (If you're not, go ahead and take a detour and familiarize yourself. In the a free trial into Safari and check out The Object-Oriented Thought Process, by Matt Weisfeld.) I'm going to take you through the building of a simple survey application. Many of the steps will seem familiar, with differences only in syntax. But there are few places where you might be surprised at how Ruby handles things.
Let's start with the very basics: input and output.
Input and Output
I'm assuming that by this point you have installed some distribution of Ruby. If you haven't, now is the time. Download a distribution from http://www.ruby-lang.org/en/20020102.html and install it.
Okay, now that that's done, create a new text file and name it survey.rb
.
In the file, add the following code:
puts "Enter the name for your survey: " surveyName = gets puts "The name is: " + surveyName
This is a very simple application, in that all that it does
is output a string, wait for you to enter some text (followed by the return
key)
and output the results. To execute the file, you'll use the
ruby
executable:
c:\myrubyfiles>ruby survey.rb Enter the name for your survey: First Survey The name is: First Survey
All right, we know that it works, but what did we learn? Well, we learned that there are no particular structures for a Ruby application, for one thing. We didn't have to create a specially formatted file, or delineate the application. We just put commands into it. We didn't even have to end the lines with semicolons. All we had to do was put each command on its own line.
Now, that doesn't mean that a Ruby application is complete chaos. Rather,
everything in a Ruby application is an object. For example, our
surveyName
variable is a String object, so we can access its
length
attribute:
puts "Enter the name for your survey: " surveyName = gets puts "The name is: " + surveyName print "The name of the survey has " print surveyName.length print " characters."
Notice that I've introduced another way to output text: the print
statement. You can also use the printf
command just as you would in Perl, although I won't cover that here.
You might also see text interpolated into a string using this form:
puts "The name is: #{surveyName}."
If you run the script now, you should see the following:
Enter the name for your survey: First Survey The name is: First Survey The name of the survey has 12 characters.
All right, that's the basics. Now let's look at creating actual classes.
Creating Classes And Using Objects
Before we start creating classes, we should have some idea of what it is we're actually going to create. In this case, we are creating a simple survey application, so we have the following entities:
We have a Survey
, which has one or more Question
s,
each of which has one or more Answer
s. Each of these entities
has specific attributes, such as the answerText
and results
for the Answer
. Let's start by creating the Survey
.
In your survey.rb
file, replace the contents with the following code:
class Survey def initialize (givenTitle) @title = givenTitle end end nameOfSurvey = "First Survey" survey = Survey.new(nameOfSurvey) puts "Survey is called #{survey.title}."
The first section, as you have probably guessed, is the class definition.
The initialize
method is actually the constructor. In this case,
we have created a constructor that takes a single argument representing the
title of the survey. We can tell that the title
is an attribute of the object
(in other words, an instance variable)
because of the @
that precedes it.
In fact, allow me to digress for a moment to talk about naming conventions. Notice that the class name is capitalized, and the method is not. Ruby uses these conventions in order to understand how to use a variable. Here is what Ruby expects:
Type of identifier | Convention | Example |
---|---|---|
Local variable | lowercase | mySurvey |
Instance variable | starts with @ | @title |
Class variable | starts with @@ | @@totalResponses |
Class name | uppercase | Survey |
Global variable | starts with $ | $systemStatus |
Alright, now that we've got our naming conventions down, let's
go back and look at the rest of the code.
First were creating a simple string variable, and assigning it a value.
Next, we're creating a new variable that is a Survey
object by
calling its constructor using the new()
method. Remember, we
only created one constructor, and that is expecting a single parameter.
Once we've created the object, we're outputting a string of text and the
title
attribute.
If you're familiar with objects, this probably seems very straightforward. However, if we run the script like this, we don't get the expected results:
demo.rb:11: undefined method `title' for #<Survey:0x2aa8240 @title="First survey"> (NoMethodError)
What happened here? Well, unless you explicitly create an accessor method, you can't get the value of an attribute. While at first this may seem to go against the "principle of least surprise", consider the fact that it means you don't have to explicitly protect any values from access. You simply provide accessors only for those you wish to access. So how do we do that?
We create a simple method:
class Survey def initialize (givenTitle) @title = givenTitle end def title return @title end end nameOfSurvey = "First Survey" survey = Survey.new(nameOfSurvey) survey.title = "Retitled Survey" puts "Survey is called #{survey.title}"
That solves the accessor problem, but we have the same problem in setting a value, as you can see if you run the script with all of these additions:
demo.rb:16: undefined method `title=' for #<Survey:0x2aa7ee0 @title="First Survey"> (NoMethodError)
So we have to create the setter method too:
class Survey def initialize (givenTitle) @title = givenTitle end def title return @title end def title= (newTitle) @title = newTitle end end ...
If you're like me, that definition might look a little nutty. But really,
you are literally defining what Ruby should do if it encounters the string
title=
. (In fact, Ruby lets you define a lot of operators this way.)
Now the script will run just fine:
Survey is called Retitled Survey
Fortunately, there is a much easier way to do this. Rather then explicitly creating individual all setter and getter methods, we can tell Ruby to do that for us:
class Survey attr_reader :title attr_writer :title def initialize (givenTitle) @title = givenTitle end end ...
The :title
notation tells Ruby that we are actually looking for the item called "title"
rather than the data pointed to by the title
variable. In fact, you can set as many attributes as you like this way using a
comma delimited list.
Now let's get down to the rest of the structure. We'll start by adding the
Answer
class to the file:
class Survey attr_reader :title attr_writer :title def initialize (givenTitle) @title = givenTitle end end class Answer attr_reader :answerText, :responses attr_writer :responses def initialize (theAnswer) @answerText = theAnswer @responses = 0 end def answerChosen() @responses = @responses + 1 end end nameOfSurvey = "First Survey" survey = Survey.new(nameOfSurvey) survey.title = "Retitled Survey" puts "Survey is called #{survey.title}"
First, notice that all of these definitions can go in a single file.
(They don't have to, but they can.) Second, notice that we have also added
a method that increments the number of responses for a particular answer,
which we have set to zero in the constructor. Finally, notice that
we can have different access for different instance variables; we can
read and write to the answerText
, but we can only write
to the responses
value.
Next up, we'll look at printing objects, and we'll put together the rest of the structure.