Ruby and Web Applications - THE RUBY WAY, Third Edition (2015)

THE RUBY WAY, Third Edition (2015)

Chapter 19. Ruby and Web Applications

O, what a tangled web we weave...!

—Sir Walter Scott, The Lay of the Last Minstrel

Ruby rose to extreme (and some might even say overhyped) popularity over the last decade or so. Although Ruby is a general-purpose language, and can be used for any programming task, the majority of Ruby’s rise to fame is the result of a single Ruby library, Ruby on Rails. Created by David Heinemeier Hansson and first released in 2004, Rails (as it is popularly known) allows developers to produce rich, interactive web applications with previously unprecedented speed.

In this chapter, we’ll examine how to respond to HTTP requests from a web browser or API client (such as a mobile application or another web service). We’ll give an overview of the advantages provided by Ruby web frameworks such as Rails and Sinatra, and examine the many tools that integrate with those frameworks to ease working with data stores, HTML, CSS, and JavaScript. Finally, we’ll look briefly at how to produce and consume HTTP APIs from Ruby, and how to generate complex static sites easily.

To start off, we’ll look at HTTP servers.

19.1 HTTP Servers

HTTP servers make up a huge proportion of the programs in service today. They provide interfaces to our communications, documents, finances, travel plans, and nearly every other aspect of life. As complex as those web apps can be, though, they are all served over HTTP, which is a very simple protocol. In essence, HTTP is just a few lines of plain text describing each request and response, all sent over a TCP socket.

19.1.1 A Simple HTTP Server

To demonstrate exactly how simple HTTP is, we will begin by writing an HTTP server in Ruby that can be accessed using any web browser. Try running Listing 19.1 and then opening the URL http://localhost:3000 in your web browser.

Listing 19.1 A Simple HTTP Server


require 'socket'
server = TCPServer.new 3000

loop do
# Accept the connection
socket = server.accept

# Print the request, which ends in a blank line
puts line = socket.readline until line == "\r\n"

# Tell the browser we are an HTTP server
socket.write "HTTP/1.1 200 OK\r\n"
# Tell the browser the body is 52 bytes
socket.write "Content-Length: 51\r\n"
# Empty line to separate headers from body
socket.write "\r\n"
# Write the HTML that makes up the body
socket.write "<html><body>"
socket.write "<h1>Hello from Ruby!</h1>"
socket.write "</body></html>\n"
# Close the connection
socket.close
end


In this server, we accept incoming requests for a TCP connection. Then, we print each line of text sent by the web browser until there is an empty line. Next, we send an HTTP Response, which is just text in a specific format that the browser can understand.

The response consists of a status code, headers, and body. In our response, we send the status code 200, which indicates a successful request and response. There are many other status codes, including redirection to a different location (301 and 302), no item at that address (404), or even an error on the server (500). For a complete list, refer to a reference online such as Wikipedia or httpstatus.es.

After the status code, we send a single header, indicating to the browser how many bytes there will be in the body we are about to send. Additional headers are optional, and can be used to indicate things such as what we are sending in the body (HTML, JSON, XML, or even a video or audio file), whether the body will be compressed, and other information.

Last, we send an empty line that indicates the headers are over and the body will follow. As you may have noticed, the line breaks are not simple \n linefeed characters, but are \r\n (the carriage return character followed by the linefeed character). A single linefeed is the standard line break on UNIX and Mac OS X machines, whereas the combined carriage return and linefeed is the standard line break on Windows machines and some other systems, as well as HTTP requests and responses.

At this point, if you have run the server and opened localhost:3000 in your browser, you should be able to see a large, bold “Hello from Ruby!” in your web browser. In your terminal, you will be able to see the exact text that the browser sent to your server. For me, the terminal output looked like this:

GET / HTTP/1.1
Host: localhost:3000
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,
*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: en-us
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4)
AppleWebKit/537.78.2 (KHTML, like Gecko)
Version/7.0.6 Safari/537.78.2
Cache-Control: max-age=0
Connection: keep-alive

This output is the contents of an HTTP request. As you can see, it is very similar to the HTTP response we created in Listing 19.1. The request opens with a line declaring the request: in this case, a GET request for the path /. The Host header indicates the domain name for the request, which is localhost. The various Accept headers indicate that the browser would like a response in HTML, XHTML, or XML, the response may be compressed, and the response should be in English. The User-Agent header indicates the request is coming from the Safari browser (version 7.0.6).

19.1.2 Rack and Web Servers

Every HTTP server accepts requests like the one we just looked at, and sends responses like the one we constructed earlier. In 2007, Christian Neukirchen created a library called Rack. Rack provides a single API for all Ruby HTTP servers and web applications to share.

Bear in mind that Rack is not for high-level development so much as for the creation of tools, libraries, and frameworks. So it is more for use by expert developers, and framework or library users do not usually see its API. Once you grasp its purpose and usage, it becomes very powerful.

In my opinion, Rack is pure genius. Since its introduction several years ago, Rack-based software has processed many trillions of requests in Ruby-based applications.

Let’s look at some details of how this works. An HTTP request consists at minimum of a hash-like set of parameters. The response that comes back comprises three parts: A status code, a set of headers, and a body.

Imagine that an object has a call method that returns an array of data in this format. Any class that follows these rules is a Rack application. Here is the simplest possible example of such a class:

class MyRackApp
def call(env)
[200, {'Content-type' => 'text/plain'}, ["Welcome to Rack!"]]
end
end

Notice that the body itself is an array rather than just a string. This is because of a convention that the body should respond to the each method. (Actually, a simple string would also work here if it responded to each as in older versions of Ruby.)

So how do we run this application? There is more than one way. Rack comes with a utility called rackup which is part of the Rack gem. Basically this is just an app runner that works with a .ru file. Here is such a file, where we just invoke the app by passing the object as a parameter to the run method.

# Assumes previous definition
app = MyRackApp.new
run app

By convention, a Rack application is set up in a Ruby file named config.ru. Using Rack’s simple API, we can rewrite our HTTP server much more simply. In this code fragment, we return the same HTTP response via Rack. Note the use of a simple “stabby lambda” rather than a more verbose solution.

run -> (env) { [
200, {"Content-Type" => "text/html"}, ["<html><body>",
"<h1>Hello from Ruby!</h1>", "</body></html>"]
] }

Every Rack application must respond to the call method, which is invoked once per request. The env argument that is passed to the call method contains information about that request, including the HTTP verb, requested path, request headers, client IP address, and more.

Because Proc objects all respond to call, the simplest Rack app is just a lambda, as in our example. Every Rack application must return a Rack response: one three-element array, consisting of the status code (as a number), the response headers (as a hash), and the body (as an object that responds to each, in this case an array).

An important concept making Rack useful is the idea of middleware. Think of a piece of middleware as an entity that sits between the browser (or client) and the server. This entity will process requests from the client to the server, and will also process responses from the server to the client.

In this way, middleware can be “chained” more or less arbitrarily. Each successive middleware component transforms the stream of information in some way. Think of the UNIX “pipe” (|) as an analogy.

There are conventions and techniques for writing your own middleware, but we won’t cover that here. We’ll just mention that there are numerous components already out there, either part of Rack or written by third parties. These enable functionality such as HTTP caching, spam traps, heartbeat checking, Google analytics, and more.

If you use Rack seriously, you may want to know the details of Rack::Builder; this is a DSL for building up a Rack application incrementally and “gluing” the various pieces into a single application. The rackup utility transforms your .ru file into a builder instance “behind the scenes”; but for more power and flexibility, you can do these operations yourself.

To run a Rack application, we can use one of the many Rack-compatible HTTP servers written in Ruby. Using a Ruby web server saves the trouble of writing and maintaining code to create a TCP server and correctly parse HTTP requests and format HTTP responses. If no servers are installed, Rack will use the Webrick server from the Ruby standard library, but it is not suitable for production applications. The most popular Ruby web server is Unicorn, which is optimized for single-threaded applications running on MRI. For more information about Unicorn, refer to the Unicorn documentation, hosted at unicorn.bogomips.org. With support for multi-threaded applications, as well as MRI, JRuby, and Rubinius, Puma is my Ruby web server of choice. For more on Puma, see the Puma website at puma.io.

Notice also the terminal output, which is now generated by the combination of Puma and Rack. This server generates just a single line of output for each request, but that line includes the IP address the request came from, the date and time, the HTTP verb, the path, the HTTP version, the status code that was returned, and the amount of time that it took to generate the response. Here is the output after starting Puma and making a single request:

Puma starting in single mode...
* Version 2.9.0 (ruby 2.1.2-p95), codename: Team High Five
* Min threads: 0, max threads: 16
* Environment: development
* Listening on tcp://0.0.0.0:9292
Use Ctrl-C to stop
127.0.0.1 - - [02/Sep/2014 16:32:26] "GET / HTTP/1.1" 200 - 0.0001

When we are using Rack, it is possible to access all the same information that we had access to when we accepted a TCP connection and read the request ourselves, but we don’t have to do anywhere near as much work. We can simply access various keys on the env hash to get the data directly. Building on top of Rack and the unified cross-server API it provides are various application frameworks such as Rails.

19.2 Application Frameworks

As you can probably imagine, web applications can quickly become complex and unwieldy, even with the abstractions provided by Rack. That is where web application frameworks like Rails and Sinatra step in. A web framework provides (at a minimum) an additional layer of abstraction, making it possible to call different methods depending on the HTTP verb, the path, or any other conditional.

Ruby on Rails is the “batteries included” framework of the Ruby world. It includes a command-line tool to create and run Rails applications, and many individual libraries that manage responsibilities such as data storage, HTML template rendering, CSS and JavaScript management, and much more.

Sinatra is much more minimal, and provides barely more than a mapping between a particular URL and some Ruby code. Any additional facilities must be provided by other libraries (and in fact many Sinatra applications also use some parts of Rails). We’ll give some examples from both Rails and Sinatra in this section, and then look at additional tools and libraries that integrate with Rails (and may be usable from Sinatra) for the remainder of this chapter.

There are other Ruby web application frameworks, including the venerable Ramaze, the brand-new Lotus, and others. If you’re interested in different ways to build a web application framework, definitely check out the other options as well. If you’re only interested in building your own web application, I recommend that you just use Rails. It has the widest adoption, the most users, and the most examples, solutions, and tutorials out there on the Web for times when more help is needed.

When a request is made, the first thing a Ruby application framework needs to do is decide what code should be run to respond to the request. This is usually called routing, and is provided by both Rails and Sinatra, albeit in different ways. We’ll look at Sinatra first, then Rails.

The examples in this chapter were tested against Sinatra version 1.4.5 and Rails 4.1.5, on Ruby 2.1.2. If newer versions are now available, your mileage may vary. If necessary, you can install those exact versions in order to try out these examples.

19.2.1 Routing in Sinatra

Building on top of Rack, the Sinatra gem provides just a little bit more functionality. Sinatra applications map HTTP verbs and paths to code blocks that will be executed if the request matches. In Listing 19.2, we create a Sinatra application that provides the same functionality as our previous example.

We even go beyond our previous example and add an additional path to our application. Without Sinatra, we would have to examine the path of the request ourselves, and call different code based on what the requested path is. Sinatra provides that ability automatically, allowing us to map any HTTP verb and path to some specific Ruby code.

Listing 19.2 A Sinatra Application


require 'sinatra'

get "/" do
<<-HTML
<html>
<body>
<h1>Hello from Ruby!</h1>
</body>
</html>
HTML
end

get "/world" do
<<-HTML
<html>
<body>
<h1>Hello, World!</h1>
</body>
</html>
HTML
end


To run this example, save Listing 19.2 into a file named sinatra.rb. If necessary, install the Sinatra gem by running gem install sinatra, and then run the server with ruby sinatra.rb. At that point, you will be able to browse to http://localhost:4567 to see our original example, and you will also be able to browse to http://localhost:4567/world to see the “Hello, World!” message.

The terminal output when running a Sinatra app is nearly identical to the output when running the Rack app. The only significant difference is that there is now a second log line, for the request to the "/world" URL.

Puma 2.9.0 starting...
* Min threads: 0, max threads: 16
* Environment: development
* Listening on tcp://localhost:4567
== Sinatra/1.4.5 has taken the stage on 4567 for development with
backup from Puma
127.0.0.1 - - [02/Sep/2014 17:36:33] "GET / HTTP/1.1" 200 51 0.0047
127.0.0.1 - - [02/Sep/2014 17:36:38] "GET /world HTTP/1.1" 200 48
0.0004

19.2.2 Routing in Rails

Next, we will look at the same example in Rails. The Rails gem itself contains very little code—instead, Rails combines other libraries that handle individual functions. The ActionController class, which is part of the action_pack gem, approaches the problem of routing somewhat differently from Sinatra. In Rails, the code that will be called is written inside a controller, and the routes.rb file specifies that a particular path should call a particular controller method.

Let’s build our example again as a small Rails application. To start with, install Rails and all its components by running gem install rails if you have not already. Then, run the command rails new hello. This will create a directory named hello containing the entire skeleton of a Rails application. For right now, we don’t care about most of those files, but to learn more about each one, you can read the “Getting Started with Rails” guide at guides.rubyonrails.org.

Next, cd hello to change directories into our new Rails application and then run bin/rails generate controller hello. Several files will be created, but the important one for our example is app/controllers/hello_controller.rb. Open that file in your editor and change it to match this code:

class HelloController < ApplicationController
def index
render inline: "<h1>Hello from Ruby!</h1>"
end

def world
render inline: "<h1>Hello, World!</h1>"
end
end

Here, we are defining two methods in the HelloController, both index and world. The names are arbitrary and can be connected to any path by the routing configuration. To add those routes, we need to edit the config/routes.rb file. This file is generated containing a lot of explanation about different kinds of routes, but for our example, we only need these four lines:

Rails.application.routes.draw do
get "/" => "hello#index"
get "/world" => "hello#world"
end

The syntax for declaring routes in Rails consists of calling a method with the name of the HTTP verb that will be routed and then passing a hash with the path as a key as well as the controller name and method in the form name#index. As you might now guess, this routes file means that a request to "/" will be served by the index method, and a request to "/world" will be served by the world method.

To run this example, execute the command bin/rails server. As you may have noticed by now, the rails command acts as a shortcut to common tasks that you may perform while building a web application using Rails. After the server has started up, browse tohttp://localhost:3000 to see the output from our example. To see the alternate output, browse to the http://localhost:3000/world URL.

This time, the terminal output is different yet again, and includes several lines per request. These lines include the elements that we can expect from the previous examples: HTTP verb, requested path, requester IP address, timestamp, the HTTP status code returned, and the amount of time it took to generate the response:

=> Booting WEBrick
=> Rails 4.1.5 application starting in development on
http://0.0.0.0:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
[2014-09-02 17:29:32] INFO WEBrick 1.3.1
[2014-09-02 17:29:32] INFO ruby 2.1.2 (2014-05-08)
[x86_64-darwin13.0]
[2014-09-02 17:29:32] INFO WEBrick::HTTPServer#start:
pid=20372 port=3000

Started GET "/" for 127.0.0.1 at 2014-09-02 17:29:32 -0700
Processing by HelloController#index as HTML
Rendered inline template (0.6ms)
Completed 200 OK in 10ms (Views: 3.2ms | ActiveRecord: 0.0ms)

Started GET "/world" for 127.0.0.1 at 2014-09-02 17:29:39 -0700
Processing by HelloController#world as HTML
Rendered inline template (0.2ms)
Completed 200 OK in 1ms (Views: 0.4ms | ActiveRecord: 0.0ms)

In the middle two lines, however, we see new information: the name of the controller and method that were called to handle the response, HelloController#index and #world. We also see that the response was generated by rendering an inline template. We’ll examine templates further in Section 19.4, “Generating HTML.”

In addition to a path, HTTP requests can include parameters, which are sets of keys and values provided by the browser making the request, usually from input given by the browser’s user. In both Sinatra and Rails, parameters can be accessed as a hash, named params. Entries inparams can come from the URL or can be sent as part of the request body if the request uses the HTTP verb POST. Using request parameters, we can add dynamic output to our examples (meaning the output changes depending on the inputs given by the client).

19.2.3 Parameters in Sinatra

We can add another example to our Sinatra application that uses one parameter from the URL and one parameter from the query string, which is the part of the URL that comes after a ? symbol. Open the file sinatra.rb, saved from Listing 19.3, and add this code to the end of the file:

get "/hello/:name" do
body = "<html><body><h1>Hello"
body << " from " << CGI.h(params[:from]) if params[:from]
body << ", " << CGI.h(params[:name])
body << "!</h1></html></body>"
end

Here, we declare a parameter in the URL by using a colon, somewhat like a symbol in Ruby. Sinatra knows to parse the URL, looking for a path such as /hello/Julia or /hello/Tim. The part of the path that is in the location where :name is will be placed into the params hash, under the key :name. The other parameter we use, from, is not part of the path. That means it will have to be provided as part of the query string, in a path that looks something like /hello/Julia?from=Ruby.

When we insert either parameter into the HTML that will be returned in the response body, we escape it using the CGI.h method. The h method is an alias for escape_html. The method takes a string as input and returns a string with HTML-specific characters escaped. This escaping is critical for security, and must always be done when a web application will be returning input taken from a user inside an HTML response.

After adding to the file, fire up the server with ruby sinatra.rb and try it out! Experiment with different URLs, changing the name and from, and observing the result. Note that if the from key is absent, the response does not say where the hello is from, and if the name is absent (for example, at the path /hello/), an error message is returned.

19.2.4 Parameters in Rails

Parameters in Rails are very similar to parameters in Sinatra. We add one additional method to app/controllers/hello_controller.rb, named hello. (Make sure the method definition is inside the class/end block.)

def name
response = "<h1>Hello"
response << " from " << h(params[:from]) if params[:from]
response << ", " << h(params[:name])
response << "!</h1>"
render inline: response
end

Then, open the config/routes.rb file and add this line, one line above the final end:

get "/hello/:name" => "hello#name"

As before, the method name name is arbitrary, but it is (hopefully) easy to remember that the path /hello/:name goes to the controller Hello and the method name. Start the server again using bin/rails server and browse to http://localhost:3000/hello/Zelda?from=Ruby to see the same response.

Note that there is a new line of terminal output this time, containing the parameters for the request. Sinatra does not log this information for every request, and instead shows only the path. Rails logs both the path and the parameters of the request, with lines like these:

Parameters: {"name"=>"Zelda"}
Parameters: {"from"=>"Ruby", "name"=>"Zelda"}

Although there is a great deal of depth available using either Sinatra or Rails, we do not have room here to explore it. For additional information about Sinatra, refer to the Sinatra website at sinatrarb.com or read Sinatra: Up and Running, by Alan Harris and Konstantin Haase.

We will elaborate slightly on the Rails example in the following sections, but comprehensive documentation is also available on the Web at rubyonrails.org/documentation and in print in The Rails 4 Way, by Obie Fernandez and Kevin Faustino.

Now that you have learned the basics of routing and parameters in Sinatra and Rails, let’s look at storing persistent data across requests using ActiveRecord with Rails.

19.3 Storing Data

In web applications, storing data becomes more difficult than storing data in other Ruby programs. HTTP, as defined, is a stateless protocol. That means that an HTTP server is not required to store information between requests. The reasons for that are technical, but they primarily boil down to the idea that it should be possible to have multiple machines running the same application, and clients should be able to get the same response from any of them.

This makes it possible to handle many more requests at a time (since any server can handle the next request, sharing the work), but it means that each individual server cannot save any information (such as user accounts) into variables or files. Variables are only available inside a single Ruby process, and files are available only on a single machine, which rules both of them out.

The solution to this problem is to use a database or data store. We looked at PostgreSQL, MySQL, and Redis in Section 10.3, “Connecting to External Data Stores,” of Chapter 10, “I/O and Data Storage.” Rather than reiterate that section here, we will use the ActiveRecord library to create, read, update, and delete data from the database using objects instead of direct SQL queries.

19.3.1 Databases

The ActiveRecord library is able to connect to many kinds of SQL databases, including PostgreSQL, MySQL, Sqlite3, and even Oracle and Microsoft SQL databases. Each table in your database is represented by a class named after that table that inherits from the ActiveRecord::Baseclass. Each row in your table is represented as an instance of that class, with reader and writer methods for each of the column names.

In this section, we’ll expand our example Rails application to remember the name of every person it has ever said hello to, and also record where that hello was said from if that parameter was present. In the upcoming section “Generating HTML,” we’ll add a form with text fields for who the hello will be said to and where it is being said from.

The first thing we’ll do is generate a model named Greeting. Model classes inherit from ActiveRecord::Base and operate on a database table that shares their name. To create the model (and a file that will add a table with the same name to the database when it is run), run the command bin/rails generate resource greeting to:string from:string. This will generate a few files, but we only care about two of them right now.

The first file is in db/migrations and has a name that starts with a timestamp and ends in create_greetings.rb. Here’s what should be inside that file:

class CreateGreetings < ActiveRecord::Migration
def change
create_table :greetings do |t|
t.string :to
t.string :from
t.timestamps
end
end
end

Now, let’s run the command bin/rake db:migrate. This will create a SQL database for your application as well as run the migration file, which creates a table named greetings with columns named to and from. Both columns will store strings. After the migration command has run, we can rewrite the name method inside app/controllers/hello_controller.rb. Change it to look like this:

def name
greeting = Greeting.create!(to: params[:name],
from: params[:from])
render inline: "<h1>" << CGI.h(greeting.to_s) << "!</h1>"
end

In this method, we use the Greeting class to create a new database row with the values of the to and from columns set by the corresponding values in the params hash. Then, we use the to_s method on the instance to create the response.

Normally, it is not a good idea to create (and especially not to delete!) database entries while responding to a GET request. Search engine robots that scrape the Internet will repeatedly activate any GET URLs they know about, as many as hundreds of times per day. In any real application, you should change data only in response to the HTTP verbs POST, PUT, PATCH, and DELETE. We create a database entry in a GET request here purely to simplify the example.

After saving the changes to that file, if you run bin/rails server and browse to one of the URLs that you tried before, you’ll see a strange response that looks something like #<Greeting:0x007fead16c1df8>!. That’s not what we want to see, so we’re going to create our own to_s method on the Greeting class that returns the greeting we expect. To do that, edit the file app/models/greeting.rb and change it to this:

class Greeting < ActiveRecord::Base
def to_s
s = "Hello"
s << " from #{from}" if from
s << ", #{to}"
end
end

This method simply reimplements the same logic we were using before, but in the model instead of in the controller. Because the controller handles HTML escaping the string, we no longer need to escape the string as we build it. After changing greeting.rb, run bin/rails server again and you will see the familiar greeting that we have been seeing this whole time.

Now that we are saving each greeting that is displayed, we will create a new controller that will display every greeting that has been sent. Note that this list will persist even when the Rails server is stopped and then started again, because it is saved in an external Sqlite3 database.

To create the new controller that will display past greetings, run bin/rails generate controller greetings index. This will add the line get 'greetings/ index' to the routes file, and create the file app/controllers/greetings_controller.rb. The route get 'greetings/index' is a shorthand for the route get 'greetings' => 'greetings#index'. Now, let’s edit the controller file to return a response that includes each greeting:

class GreetingsController < ApplicationController
def index
greetings = Greeting.all
body = "<h1>Greetings</h1>\n<ol>\n"
greetings.each do |greeting|
body << "<li>" << CGI.h(greeting.to_s) << "</li>\n"
end
body << "</ol>"
render inline: body
end
end

In this action, the all method loads every row stored in the database in the greetings table, converts each row into an instance of Greeting, and then returns an array of those instances. We use the each method to iterate through that array, adding each greeting to the response. After saving this file, run the server again using bin/rails server and browse to http://localhost:3000/greetings.

Depending on how much experimentation you did after we added the Greeting model, you might see a long or short list of greetings. Either way, be sure to get a new greeting and then visit the list of greetings again to see that the new greeting has been added to the list.

This concludes our brief look at storing data using ActiveRecord. It is far more complex of a topic than we have room to cover here, and entire books could be (and have been) written about using it. For additional information about using ActiveRecord, refer to the ActiveRecord guides atguides.rubyonrails.org and in The Rails 4 Way.

19.3.2 Data Stores

ActiveRecord is merely one of many object-relational mappers (ORMs) written in Ruby. An ORM is simply a library that contains code to map stored data into Ruby objects, allow the objects to be changed, and then map those objects back into data that can be stored. There are ORMs for many non-SQL data stores, including Mongoid for MongoDB, Couchrest for CouchDB, redis-objects for Redis, among others.

In the vast majority of cases, web applications are best served by the widely used open-source SQL databases PostgreSQL and MySQL. Therefore, in the interest of space, we will not give example usages for any non-SQL data stores. However, we encourage you to research and investigate the different capabilities offered by other data stores.

19.4 Generating HTML

It’s possible that you have noticed, especially in the previous examples of this chapter, that creating HTML responses by concatenating strings can be awkward. (If you’re not yet familiar with how HTML works, the rest of this section will probably make more sense if you read about it first. The Mozilla Developer Network reference on HTML, located at developer.mozilla.org/docs/Web/HTML, is probably a good place to start.)

The more HTML there is present in a response body, the more awkward it is to construct that HTML using strings. Rather than make everyone add strings together, most web frameworks (including Rails) allow the use of templates.

Templates are files written in a templating language that can be converted into HTML on demand. Often, they contain Ruby code that inserts the contents of variables into the HTML. Templates can be nested, with the output from one template being inserted into another template.

Usually, using templates means creating one (or sometimes more) layouts, which contain the HTML making up the header and footer of your site. The layout will be used for every page, while the template that is rendered by the controller will go inside the layout. Finally, small template fragments (such as those used inside a loop) can be extracted into partials. Each individual template uses a single templating language, but layouts, regular templates, and partials do not need to share a templating language to be used together.

The most common templating language, and the default with Rails, is ERB. ERB is part of the Ruby standard library. It looks an awful lot like HTML (or maybe more accurately, like PHP), and it is ultimately a tool for inserting Ruby strings into HTML as easily as possible.

19.4.1 ERB

Using ERB by itself is very, very easy. Here’s a simple example that prints the solution to a math problem:

require 'erb'
puts ERB.new("two plus two is <%= 2 + 2 %>").result
# Output: Two plus two is 4

ERB consists of text containing erb tags, which can look like <%= code %> or like <% code %>. With the equals sign, the value of the expression is interpolated into the file. Without the equals sign, the expression is evaluated, but nothing is inserted into the file. The tags without equals are mainly used with if or each and their corresponding end statements.

Using ERB from Rails is also very easy. In fact, it is the default. If a controller action does not render anything, Rails will look for a template with the name of the action in a directory named after the controller, and return the results of rendering that template.

To demonstrate this simple example of templates, let’s re-create our first example using a template instead of using the controller. First, we’ll need to delete the contents of the HelloController method named index, leaving just the empty method definition:

def index
end

Next, we’ll need to create the template that we want Rails to use. Create the file app/views/hello/index.html.erb and then put our usual message into it:

<h1>Hello from Ruby!</h1>

Once that file is saved, you can start the application with bin/rails server and browse to http://localhost:3000 to see the message. If you view the terminal output, you will be able to see that Rails has rendered the template named hello/index:

Rendered hello/index.html.erb within layouts/application (0.7ms)

Next, let’s convert the list of greetings that we created in the last section to use a template instead. Edit the index method in app/controllers/greetings_controller.rb to contain this code:

def index
@greetings = Greeting.all
end

In Rails, instance variables that are set in controller methods will be available as instance variables inside the template when it is rendered. To take advantage of this fact, edit the template we generated earlier at app/views/greetings/index.html.erb. Change the template to contain this ERB code:

<h1>Greetings</h1>
<ol>
<% @greetings.each do |greeting| %>
<li><%= h(greeting.to_s) %></li>
<% end %>
</ol>

This template is nearly identical to the code we had previously written inside the index method. The main difference is that we are able to write HTML directly into the file, without having to put it into a string variable. ERB takes care of replacing the ERB tags with the results of running the Ruby code inside them.

Templates in Rails are given some additional helper methods, including the h method, which does the same thing as the CGI.h method we were using earlier. Note that even inside a template, we still need to HTML-escape the greeting text because part of it came from user inputs.

After changing the controller and template, restart the Rails server and visit http://localhost:3000/greetings in your browser. You’ll be able to see the same list of greetings as you were seeing before, but the controller method has been reduced to a single line of code.

This example now includes all three parts of the MVC (Model View Controller) paradigm that Rails espouses. Data storage is handled by interacting with the model class, per-request logic is executed by the controller, which then hands of data to the view, which is used to render HTML. The rendered HTML is then returned in the HTTP response body, and the request is complete.

The tooling available for using templates in Rails is far more complex than we have room to cover here. Although we must continue to Haml, another popular templating system, be sure to investigate the powerful rendering system of layouts, templates, and partials that Rails makes available. For more information, refer to the template guides at guides.rubyonrails.org and, of course, in The Rails 4 Way.

19.4.2 Haml

The Haml library is a templating language very different from ERB. Instead of being HTML with tags inserted, Haml is a terse language that declares HTML tags primarily using punctuation. It avoids the need for closing tags by making indentation meaningful, and does not require any angle brackets.

To use Haml in our Rails example, edit Gemfile and add the line gem "haml". Then, run bundle install to add Haml to the bundle of gems that will be loaded when the Rails app starts. For more information about Bundler and how it works, refer to the Bundler website at bundler.io.

To illustrate how Haml is different from ERB, we’ll convert the list of greetings from ERB to Haml. The first step is to rename the template file in app/views/greetings from index.html.erb to index.html.haml. The first extension indicates to Rails what type of file will be produced, and the second extension indicates what templating system to use to produce that output.

Edit the template at app/view/greetings/index.html.haml and change it to contain this Haml code instead:

%h1 Greetings
%ol
- @greetings.each do |greeting|
%li= h(greeting.to_s)

As you can see in this example, neither HTML closing tags or Ruby end lines are necessary. The % symbol at the start of a line indicates an HTML tag, and the rest of the line indicates the contents of that tag. An = symbol indicates that the line contains Ruby code and that the tag should contain the results of running that Ruby code, rather than the literal contents of the line. Putting == after the name of the tag indicates that the line contains a Ruby string and should allow string interpolation as usual via #{}.

Many Ruby web developers find Haml more aesthetically pleasing, less repetitive, and dramatically faster to write than ERB. As useful as it can be for writing a large number of tags, though, Haml can make it very difficult to write a large amount of text. For text-heavy pages, ERB is usually easier.

Haml provides a rich API with many options, and it offers a compelling alternative to ERB. For more information about Haml, see the Haml website at haml.info.

19.4.3 Other Templating Systems

ERB and Haml are definitely the most popular templating systems in Ruby, but they aren’t the only ones. Other systems take different approaches to building HTML. Slim tries to require as little input as possible. Writing a template in Slim requires even fewer characters than the same template written in Haml.

The Liquid engine, developed for the Shopify online store generator, only allows certain bits of code to run inside it, such as if statements and each loops. This makes it safe for Liquid templates to be supplied to users because the lack of code prevents security exploits.

The Mustache library takes things even further, and doesn’t allow templates to contain any logic at all. Any code must be executed before the template is rendered, in an object that prepares the data for the template.

If neither ERB nor Haml strike your fancy, take a look around! Chances are good that there is a templating engine that meets your wants or needs. And if you don’t find one, be assured that writing a templating engine is a time-honored tradition among Rubyists, so feel free to write one of your own.

19.5 The Asset Pipeline

If you spend much time browsing the Web, it’s possible that by now you have noticed two things that are missing from our example application that are present on nearly every website today: Cascading Style Sheets (usually just called CSS) for visual styling and JavaScript for user interaction.

Rails provides a unified system for managing CSS and JavaScript. In development, it is very useful to have access to each CSS and JavaScript file for experimentation, debugging, and the like. In production, however, it is far more efficient to combine everything into one CSS file and one JavaScript file. This reduces the number of HTTP requests needed, and speeds up loading each page.

Tooling to automate this process is included with Rails, and is referred to as the asset pipeline. Every file in app/assets is processed by the asset pipeline and made available as separate files in development and combined in development. The combined files are also stripped of comments, whitespace, and everything else that can be removed, to make them as small as possible.

Similar to the way templates are rendered, assets can be written in one language but output in another language. Our first example of this is the SCSS language, which is processed into CSS.

19.5.1 CSS and Sass

Sass, which its creators have sometimes claimed stands for “Syntactically Awesome Style Sheets,” is the processor for the SCSS language. SCSS is a superset of CSS. (If you are not yet familiar with CSS, this section will probably not be terribly helpful. The Mozilla Developer Network also offers reference and tutorial material on CSS, which can be found at https://developer.mozilla.org/docs/Web/CSS.)

SCSS being a superset of CSS means that all CSS is valid SCSS, but there is significant additional functionality available as well. The biggest additions made by SCSS include variables, nesting, partials, inheritance, and mathematical operators.

The sass-rails gem was included automatically in our hello application, so we can alter the visual display of our example application right away by adding to an existing SCSS file. Open the file app/assets/stylesheets/greetings.css.scss. At the bottom of that file, add these lines to change how our list of greetings looks:

body {
font-family: "Avenir", "Helvetia Neue", Arial;
}

h1 {
text-shadow: 2px 2px 5px rgba(150, 150, 150, 1);
}

ol {
margin-left: 15px;
li {
margin-bottom: 10px;
}
}

After saving that file, make sure that the Rails server is still running and then reload the page at http://localhost:3000. The list of greetings should look different. The title “Greetings” should appear to have a subtle shadow behind it, and each greeting in the list should now be separated from the edge of the page and from the other items by some white space.

SCSS code is, like CSS, composed of selectors and rules. Selectors identify specific HTML tags that should be affected by the rules, whereas the rules specify what visual changes should be made. In the preceding SCSS, we change the font that will be used inside the body tag (which is all visible text on the page). Then, the h1 header tag is given a gray background shadow that highlights it and “lifts” it from the page. In the last set of rules, each ordered list (the ol tag) is given a left margin of 15 pixels, and every list item (li tag) inside of an ol is given a bottom margin of 10 pixels.

These changes are simple but demonstrate the entire workflow for stylesheet assets. Files located in app/assets/stylesheets are converted into CSS if necessary (using the same file extension scheme as templates use). Then, the resulting CSS is served to the client web browser, which uses it to change the visual display of the HTML that was in the HTTP response body.

Chris Eppstein, one of the authors of Sass, has also created Compass, which is a library of prewritten rules that can be imported and included into SCSS files. Compass collects a large number of commonly used rules that provide cross-browser compatibility, layout management, and typography, as well as rules that will be part of the CSS3 standard but are not yet supported by all browsers. For more information on Compass, see its website at compass-style.org.

Even without Compass, Sass is a useful and powerful tool for any developer who needs to write and manage CSS. For more information about Sass, start with the Sass website at sass-lang.com. Also note that there are other CSS preprocessors besides Sass, including Less and Stylus. If Sass doesn’t seem that great to you, perhaps one of the other options will.

Now that we’ve seen how Rails handles stylesheets, let’s take a look at how Rails handles JavaScript.

19.5.2 JavaScript and CoffeeScript

Over the years, web applications have become more complex, richer, and more interactive. Well-known examples of so-called “rich client” applications include Google’s Gmail and Google Docs, Microsoft’s Office 365, and Apple’s iWork for iCloud. Each of these web applications uses a vast amount of JavaScript to produce a website that, inside a web browser, closely mimics the appearance and functionality of a complex Windows or Mac OS X application.

For some websites, this type of rich interaction is a requirement. Therefore, in response to this trend, JavaScript frameworks have risen to assist with building richer and more interactive applications. Different JavaScript frameworks target different points on the richness-versus-simplicity spectrum, including Ember, Angular, React, Backbone, and even Batman.js. There are dozens of JavaScript frameworks, with what seems like a new one every week.

Using the asset pipeline, it is possible to add one or more of these JavaScript frameworks to your Rails application. For some frameworks (such as Ember and Angular), the Rails app acts primarily as a JSON API, providing data that is used by a JavaScript application running in a web browser. For other frameworks (such as React and Backbone), the Rails application can serve HTML, JSON, or a combination of the two depending on how the Ruby and JavaScript code is written. For more discussion of JSON APIs, see the next section of this chapter.

Similar to how SCSS can be processed into CSS, JavaScript has a popular language that can be compiled down into JavaScript that browsers can run. CoffeeScript adds many things that its creators felt JavaScript was lacking, including adding iterators, removing almost all parentheses, adding syntax for creating functions, and others.

To demonstrate how using CoffeeScript works in a Rails application, we’re going to add some code that adds a new greeting to the list of greetings every time the “Greetings” header is clicked. Edit the file app/assets/javascripts/greetings.js.coffee and then add these lines to the end of the file:

$('body').ready ->
$('h1').click () ->
$.ajax "/hello/Hilda?from=Rails",
success: (data) ->
item = $.parseHTML('<li>' + $(data).text() + '</li>')
$('ol').append item

The JavaScript code that results from this CoffeeScript can be viewed in your browser by navigating to the URL http://localhost:3000/assets/greetings.js—and we also reproduce it here:

(function() {
$('body').ready(function() {
return $('h1').click(function(e) {
return $.ajax("/hello/Hilda?from=Rails", {
success: function(data) {
var item;
item = $.parseHTML('<li>' + $(data).text() + '</li>');
return $('ol').append(item);
}
});
});
});
}).call(this);

In this example, we use the jQuery JavaScript library (accessible via the variable $) to find the body tag and then supply a function that will be run once the browser has finished rendering and the body is “ready.” Inside that function, we find the h1 tag and pass a function that will then be called any time the h1 tag is clicked. Inside that function, we use jQuery’s ajax method to request a specific greeting from the /hello URL that we set up earlier in our example. Finally, if the request was a success, we create a new li tag that contains the text from the response body, and add it to the end of the ol list on the page. It is not indicated explicitly, but if the Ajax HTTP request were to fail, nothing would happen. To handle failures, another function must be provided under the key failure.

Although this is an extremely simple example of both CoffeeScript and jQuery, it provides a taste of the kinds of things that can be done from within a Rails application by using asset pipeline. Many web applications have expanded from beginnings as humble as these into gigantic, monolithic Rails applications that result in thousands or even millions of dollars worth of revenue.

As this very small example demonstrates, CoffeeScript is arguably shorter, cleaner, and easier to understand than the equivalent JavaScript. This difference can be compounded in larger and larger codebases, making equivalent JavaScript code significantly longer. CoffeeScript comes with some downsides, though. The biggest downside is that CoffeeScript adds its own for-loop and class-based inheritance system on top of JavaScript.

Why is that a downside, you ask? Well, JavaScript will be gaining its own for-loop and class-based inheritance system in the next major revision the language, which is known as ECMAScript 6. ES6 (as it is abbreviated) strives to address many of the shortcomings that motivated the creation of CoffeeScript, but in a way that is similar to existing JavaScript, rather than significantly different.

As is usual with these sorts of programming conundrums, there are tradeoffs in both directions. I, for one, have stopped using CoffeeScript, knowing that it will not be compatible with the next version of JavaScript. For others, the increase in speed (or perhaps the decrease in parentheses) is more valuable, and CoffeeScript is completely worthwhile for them.

In order to learn more about CoffeeScript, refer to its website at coffeescript.org. To learn more about JavaScript, I recommend the Mozilla Developer Network’s reference and tutorials, which are located at developer.mozilla.org/docs/Web/JavaScript.

19.6 Web Services via HTTP

Finally, it’s time to mention the ways that programs on the Internet talk to each other, rather than directly to a human being. API stands for application programming interface, but is usually just used as shorthand to refer to an interface that one program can use to interact with another.

In the bad old days of networked programming, network APIs might mean writing your own socket client and server programs, as in Chapter 18, “Network Programming.” More recently, it has grown to most commonly mean making HTTP requests from your program to an HTTP server that provides a documented set of URLs.

The Ruby standard library’s HTTP library, Net::HTTP, is a functional client for interacting with these HTTP APIs. Using it can sometimes be baroque or tedious, so other gems exist to provide a smoother API, including http, excon, and typhoeus.

Interacting with HTTP APIs can be quite straightforward, though, even without one of those libraries, especially when using Ruby’s built-in open-uri:

require 'open-uri'
response = open("http://mywebstore.com/products?page=5")

After this code has run, the response.read method call will return the HTTP response body as a string. Headers can be accessed using the [] method, as in response["Content-Type"], which will return the value of the Content-Type header as a string.

Using these HTTP libraries, you’ll find it quite straightforward to interact with other websites from your own Ruby programs.

19.6.1 JSON for APIs

During the 1990s and early 2000s, it was most common to use XML (eXtensible Markup Language) to encode the data sent in API requests and responses. Primarily due to XML’s complexity and verbosity, it has fallen out of favor. Replacing it is the terse, minimal JSON serialization standard.

JSON stands for JavaScript Object Notation, but it has become an ISO standard that is widely used to transmit data between programs in nearly any programming language. Developing web applications will very likely include interacting with HTTP APIs that provide JSON responses.

The Ruby standard library includes a JSON library, which can parse JSON into Ruby hashes as well as dump Ruby hashes into JSON. Other libraries exist to provide specific additional features, such as Yajil’s JSON stream parsing, or Oj’s faster parsing core written in C instead of Ruby.

If the response we fetched in the last example contained an array of products encoded as a JSON object, we could parse the JSON into a Ruby hash and access the array of products with code like this:

require 'json'
products = JSON.parse(response.body)["products"]
# products is now an array of hashes, parsed from
# the JSON string returned by the API

The hash of results can be used as input for any task, allowing your program to act based on data provided the other server. For a real-world example of interacting with a JSON API, see Section 15.2, “Working with JSON,” in Chapter 15, “Ruby and Data Formats.”

19.6.2 REST (and REST-ish) APIs

REST (REpresentational State Transfer), first defined in 2000 by Roy Fielding, is a style of designing software so that it can be interacted with in a predictable way. The ideas behind REST were strong influences on the design of HTTP version 1.1, and provided HTTP with abilities that were largely unused by web developers or browsers. Many years later, parts of the REST philosophy have been adopted by Rails to provide conventional URLs and standard ways to execute Create, Read, Update, and Delete (CRUD) actions in a Rails application.

Rails maps the CRUD operations to different HTTP “verbs,” or actions that are allowed by the HTTP standard. Create is done using HTTP’s POST, Read using GET, Update using PATCH, and Delete using DELETE.

A hypothetical RESTful API for interacting with a catalog of books might look something like this:

GET /books # Lists all of the books
POST /books # Creates a new book
GET /books/1 # Lists information about book 1
PATCH /books/1 # Updates information about book 1
DELETE /books/1 # Deletes book 1 from the list

APIs designed according to these principles are standardized enough that there are Ruby libraries for interacting with REST APIs easily, such as rest-client, httparty, and faraday.

Although Rails dramatically increased the usage of HTTP verbs in web development, what Rails calls “REST” is something simpler but much less powerful than Fielding’s original idea. Developers working toward the original idea of REST have taken to calling it “Hypermedia,” as a way to distinguish it from the watered-down version that is built in to Rails and other frameworks.

I encourage any developer who needs to (or is simply interested in) creating HTTP services to learn more about REST, both in its initial form and the form that Rails provides. For further development of the concepts in Fielding’s original conception of REST, search for discussions of “hypermedia” online.

19.7 Generating Static Sites

While Ruby has gained popularity for building dynamic web applications, it has become a popular language for tools that generate static sites. In a static site, there is no web application running code to handle each incoming request. Instead, a web server simply finds a file on disk whose name matches the request path, and returns the contents of the file in the response body.

The web server in question might even be one written in Ruby, such as Puma or Unicorn. However, it is far more likely that a static site will be served by one of the well-known servers that are heavily optimized for serving static files and serve most of the sites on the Internet, such as Apache or Nginx (which is pronounced “engine x”). Strictly speaking, a so-called “static site” may contain interactive or dynamic elements, implemented with JavaScript. The significant factor is that the site consists of unchanging HTML, CSS, and JavaScript.

In this section, we’ll build a static site that is similar to our Rails “Hello” example. Because static sites can’t run code for every request, we’ll have to settle for a few specific greetings, rather than dynamically generating a new greeting for every request.

19.7.1 Middleman

The Ruby static site generator Middleman provides an environment that is extremely similar to a Rails application, but the resulting site is a set of files that can be served by any HTTP server. To use Middleman to create a static site, start by installing the gem with gem install middleman. The gem includes the middleman command, which provides several subcommands to assist with creating static sites. To see a list of all the available commands, run middleman help.

Once Middleman is installed, let’s create a new project by running middleman init hello_world. This creates the directory hello_world, and fills it with a (mostly empty) site. To see what the site looks like, cd into the directory and then run bundle exec middleman server to start the preview server, and then browse to http://localhost:4567. Much like the Rails server, the Middleman server allows you to quickly see changes that are made to your site while you are developing it.

When you are finished working on your site, you can stop the Middleman server and instead run middleman build. The build command creates the final static site, placing it in the public directory inside the Middleman project. After the static site has been generated, it can be deployed to production by simply copying the files in the public directory to the HTTP server that will be serving it.

Because we want our site to show a greeting, edit the file source/indexhtml.erb to contain this text instead:

title: Hello from Middleman!
<h1>Hello from Middleman!</h1>

After saving the file, you can reload the page at http://localhost:4567 to see the results of your changes. Because Middleman creates static sites, the only URL paths we can use are those that correspond to files. To add a greeting located at /world, we’ll need to add a file. First, create a new directory by running mkdir source/world. Then, create a new file named source/world/index.html.erb and add our message to it:

<h1>Hello, World!</h1>

Now, you can browse to http://localhost:4567/world and see that greeting. At this point, you may be wondering why we had to create a directory named world and put our index.html.erb template inside it. The reason ultimately comes down to prettier URLs.

Static site servers look file files by their exact name, including extension. Request paths that do not include an extension, like /world, will fall back on searching for a directory. If the directory contains an index file, that file is served automatically. Thus, by creating an index file for the directory world, we can view our greeting at the path /world. If we had merely created the file world.html.erb, we would only have been able to view our greeting at the path /world.html.

Static sites generated by Middleman provide most of the same utilities and helpers provided by Rails applications, including helper functions in templates, a full asset pipeline with Sass, Compass, and CoffeeScript integration, and more. For a complete rundown of the features available in Middleman sites, read the Middleman documentation located at middlemanapp.com.

19.7.2 Other Static Site Generators

Another popular static site generator written in Ruby is Jekyll. Jekyll uses the Liquid templating language for its templates, but uses Markdown for the contents of each page or post. Jekyll was created by one of the co-founders of GitHub, and it is used at GitHub to generate static sites for projects hosted there. Because GitHub provides hosting for open-source projects, many gem documentation websites are located on GitHub, generated with Jekyll. To read more about Jekyll, start with the Jekyll website at jekyll.com. For more about GitHub’s free static site hosting, seepages.github.com.

Built on top of Jekyll, Octopress is a set of extensions and tools specifically designed to make it easy to create a blog that is published as a static site. Octopress uses Jekyll underneath, but supplies everything that is needed to start writing blog posts right away. It includes a blog template, stylesheets, support for Disqus comments, syntax highlighting for code snippets included in posts, and a huge number of Octopress-specific plug-ins that add additional features. To learn more about Octopress, visit octopress.org.

Although not as popular as either Middleman or Jekyll, the Nanoc static site generator is the oldest static site generator written in Ruby. First released in 2007, Nanoc is still actively maintained in 2014. It offers its own take on static site generation, billing itself as “fit for building anything from a small personal blog to a large corporate website.” Take a look at Nanoc if you’re looking for another option, or are just interested in an open-source project that has continued to thrive for many years. Nanoc’s website is located at nanoc.ws.

19.8 Conclusion

In this chapter, we looked at low-level details of HTTP, and implemented our own minimal HTTP server. We reviewed frameworks and tools that make creating web applications easier, including Puma, Rails, Sinatra, ActiveRecord, ERB, Haml, Sass, and Less. Finally, we examined ways to communicate between web applications and services via HTTP APIs, and looked at Middleman and Jekyll for generating static site content.

Now let’s look at network programming in a much simpler but more abstract way. The next chapter deals with distributed Ruby.