So we've built a complete Rails application, but there is still much left to learn.

No one book could sufficiently cover everything that a developer might need to know, but there are a handful of things pertaining to Rails that are worth taking a look at before bringing this book to a close.

We'll definitely want to take this opportunity for an specific, intentioned pass over performance and security, but first, let's look into some languages and frameworks that are often put to use with Rails.

We won't be digging particularly deep into these topics, just enough to give a frame of reference as to what they generally are.

11.1.1 | Haml

Writing the views in this book was a bit difficult for me, because I don't normally write ERB. In fact, I really don't write that much HTML.

We certainly have to serve HTML from our application, so how do I get away without writing it?

With Haml.

Haml (HTML abstraction markup language) is based on one primary principle: markup should be beautiful. - http://haml.info

Haml is a brilliant shorthand for HTML that is incredibly easy to use with Rails. It even allows for dynamic population like ERB, all while using a cleaner* syntax.

  • As always, some people really don't care for Haml. I am not one of those people.

But we've already talked about HTML shorthand, it's called Markdown. Why do we need another?

Markdown is useful for content; Haml is useful for structure.

For example, we would want to write a chapter of a book or a blog post in Markdown, but we'd write their views in Haml.

Take a look at the Haml for the credit card number field from app/views/charges/new.html.haml:

...
  .control-group
    %label.control-label Credit Card Number
    .controls
      %input#number.text_field{:type => "text", :value => "4242424242424242"}
...

And compare it to the HTML it will generate:

...
  <div class="control-group">
    <label class="control-label">Credit Card Number</label>
    <div class="controls">
      <input class="text_field" id="number" type="text" value="4242424242424242" />
    </div>
  </div>
...

There are a number of interesting things going in the Haml above, but perhaps the most noticable is the complete lack of anything resembling a closing tag. The reason closing tags aren't needed is that Haml makes use of significant whitespace for the closing and nesting of elements. This means that each tab (displayed as a double space) in front of a line is actually parsed as part of the language and dictates what element an element belongs to and when it closes.

Next, we see that we open elements differently. The syntax of <input> is replaced with %input.

Following these we're free to use CSS style syntax to define id's and classes, like so: %input#id-name.class1.class2.

Stranger yet, there are places where we only see CSS style classes, such as .controls and .control-group. The reason for this is that if we don't specify an element type, Haml assumes that we want a %div. <div>'s are so common in HTML that this is incredibly helpful. Because of this assumption on Haml's part, .controls is equivalent to %div.controls.

Which, in turn, is equivalent to <div class="controls">.

Furthermore, attributes can be assigned by using a Ruby hash syntax, so %input{type: 'text'} is equivalent to <input type="text">.

As for dynamically populating views, Haml offers functionality similar to ERB with a different syntax.

To execute Ruby, but not print it's return into the rendered HTML, we use <% ... %> in ERB, like so:

<% content_for :meta, tag(:meta, content: Stripe::PUBLISHABLE_KEY, name: 'stripe-pub-key') %>

In Haml, we simply use -, like this:

- content_for :meta, tag(:meta, content: Stripe::PUBLISHABLE_KEY, name: 'stripe-pub-key')

For printing a value we use <%= ... %> in ERB:

<input class="text_field" id="email" type="text" value="<%= current_user.email || '' %>"/>

But in Haml, we can just run Ruby normally in the attribute hash:

%input#email.text_field{type: 'text', value: current_user.email || ''}

And we can use = elsewhere:

= link_to bookmark_path, 'Bookmark'

To use Haml in your project, all you have to do is add gem 'haml-rails' to your Gemfile (gem 'haml' works too but won't default to Haml for generators), $ bundle install, and end your view names in .html.haml instead of .html.erb.

11.1.2 | Sass/SCSS

I don't write enough of anything like CSS to really write anything much on Sass/SCSS, but it is definitely something to look into

Especially since Rails has recently adopted SCSS (as you can tell by all of our generated .css.scss files).

SCSS offers variables and style nesting, while Sass offers that plus significant whitespace (much like what we just saw in Haml). They both end up as plain, old CSS when they are served to the client.

11.1.3 | CoffeeScript

CoffeeScript is a wonderful language that is interpreted server-side into and then served as JavaScript. It also continues the trend of using significant whitespace to make developing in client-side languages easier.

Well, at the very least it doesn't force us type as many curly braces.

Since CoffeeScript "compiles" into JavaScript, it can only do what JavaScript can. That said, CoffeeScript adds some new syntax (some of which is inspired by Ruby) and encourages JavaScript best practices (e.g. forces == to mean ===).

As you might have guessed by our generated .js.coffee files, CoffeeScript is yet another language adopted in Rails, and as such I strongly recommend that you to take a look.

CoffeeScript's site has a ton of examples and even let's you try them in the browser.

Sadly, I don't have the time to include a CoffeeScript tutorial in this book, but the link above will more than get you started.

Why weren't these languages used in the book?

As much as I wanted to use Haml, Sass, and CoffeeScript for the tutorials, I decided that a foundational understanding of web programming needed to involve a strong focus on HTML, CSS, and JavaScript themselves.

The three languages we just glanced at are incredibly helpful for generating HTML/CSS/JS, but to appreciate their full helpfulness it is first necessary to understand the (arguable) clumsiness and frustration associated with the languages that they "compile to" and that actually appear in the browser. Starting with Haml/Sass/Coffeescript without understanding HTML/CSS/JS would be as ridiculous as trying to enjoy a parody having never experienced the original work.

And really, there is no getting away from HTML, CSS, and JavaScript. We can make our jobs easier on the server with these various technologies, but ultimately what are we going to end up sending back to the client to be rendered in the browser?

HTML. CSS. And JavaScript.

So there is that functional component as well: when things go wrong, we need to debug things as they actually are in the browser. This can become a particular issue with CoffeeScript, as it will often throw completely unhelpful errors in browser, errors that are only mere hints to the real problem when read by a developer who understands JavaScript.

I can't say for sure, but I imagine that these errors read as pure, unbridled gibberish to someone who's never worked with JavaScript. And I do not wish that on anyone.

Really, the purpose of Haml, Sass, and Coffeescript parallel the purpose of Rails itself: Rails is only helpful if you understand the difficulties of developing web applications. In the same way, these languages are only helpful if you understand the languages they result in client-side.

Having said all of that, I highly recommend looking into and learning more about all of these languages just as you continue to deepen your knowledge of HTML, CSS, and JavaScript.

11.1.4 | YAML

YAML is used frequently in Rails for storing things like configuration and locale data, and is a recursive acronym that stands for "YAML Ain't Markup Language".

YAML is similar to JSON in that it is a data serialization and interchange format, but is much more robust in its capabilities. For instance, YAML allows for the serialization of native language data types, such as Ruby objects, something JSON cannot do.

That said, most frequently in Rails, we will see YAML used to store hashes and/or arrays in a human-readable way. Let's take a look at an example in $ rails console:

> puts ({'foo' => [1,2,3], 'bar' => {'baz' => 'boo'}}).to_yaml
---
foo:
- 1
- 2
- 3
bar:
  baz: boo
=> nil

An example of YAML in our application would be config/database.yml:

### config/database.yml ###

development:
  adapter: sqlite3
  database: db/development.sqlite3
  pool: 5
  timeout: 5000

test:
  adapter: sqlite3
  database: db/test.sqlite3
  pool: 5
  timeout: 5000

production:
  adapter: sqlite3
  database: db/production.sqlite3
  pool: 5
  timeout: 5000

To see how Rails actually makes use of a file like this, let's parse the contents of this file in rails console and convert it to Ruby:

> yaml = YAML.parse File.open('config/database.yml')
=> #<:nodes::mapping:0x00000003e8bd88 ...>

> yaml.to_ruby
=> {"development"=>{"adapter"=>"sqlite3", "database"=>"db/development.sqlite3", "pool"=>5, "timeout"=>5000}, "test"=>{"adapter"=>"sqlite3", "database"=>"db/test.sqlite3", "pool"=>5, "timeout"=>5000}, "production"=>{"adapter"=>"sqlite3", "database"=>"db/production.sqlite3", "pool"=>5, "timeout"=>5000}}

> yaml.to_ruby.class
=> Hash

> db = yaml.to_ruby
=> {"development"=>{"adapter"=>"sqlite3", "database"=>"db/development.sqlite3", "pool"=>5, "timeout"=>5000}, "test"=>{"adapter"=>"sqlite3", "database"=>"db/test.sqlite3", "pool"=>5, "timeout"=>5000}, "production"=>{"adapter"=>"sqlite3", "database"=>"db/production.sqlite3", "pool"=>5, "timeout"=>5000}}

> db['development']['database']
=> "db/development.sqlite3"

As you can see from the return from the YAML.parse call, YAML uses Psych to parse YAML.

11.1.5 | Underscore

An increasingly popular JavaScript utility library is Underscore.

It offers functions like .first() and .last() to be used on arrays, as well as collection functions we have in Ruby like .map().

Underscore isn't a solution for anything specific on its own, but it can be incredibly helpful in generally letting us focus on what we're building instead of reinventing, say, the .map() function.

Here's an example of the Underscore's .map() (as seen on the Underscore site):

_.map([1, 2, 3], function(num){ return num * 3; });
=> [3, 6, 9]

11.1.6 | Backbone

Backbone.js is a client-side MVC framework that provides a clean, consistent structure for your JavaScript that interacts with a web application, especially if that application is written in Rails.

In addition to the standard benefits of requesting data as JSON by XHR, one particularly nice Backbone.js is that it provides a standard means of rendering views using JavaScript Templates (JST) instead of writing line upon line of jQuery to build elements and put them together.

Using Backbone in conjunction with CoffeeScript is particularly awesome.

There are even .hamlc (Haml CoffeeScript) templates available through the haml_coffee_assets Gem.

11.2 | Security

Security is a topic that probably deserves its own chapter (or book), but we'll just be taking a look here.

To get a thorough rundown of all the potential dangers, check out this Rails Guide on security.

11.2.1 | Mass Assignment and attr_accessible

We've seen attr_accessible used in every one of our models, but we haven't yet talked about why exactly it's there.

attr_accessible is used to whitelist attributes for writing by mass assignment.

In short, listing attr_accessible :title in Chapter allows things like Chapter.create title: params[:title] to write a title to the DB. This is fine, because we want the author to be able to use our the client UI to do just that.

But speaking of the author, we don't want just anybody to be an admin.

Imagine that we had a users#update action that would take requests to update users' names and emails. If we had attr_accessible :admin in User then all a hacker would have to do to grant themselves admin access to our app is use curl or the like to do a PUT /users/:their_id { user: { admin: true } }.

In short, attr_accessible serves as a list attributes that normal users should be allowed to write to.

How then do we access these attributes?

Remember our User activation from earlier? We do self.active = true; self.save to activate the user. Writing values to the database by this means is allowed, even though :active is not listed in attr_accessible for User, because users are not going to be able to actually write and execute any Ruby in our application.

There is also a attr_protected method that will blacklist attributes for which we don't want to allow writing of attributes by mass assignment, but its use is almost universally discouraged.

The reason for this is that it's easy to forget to blacklist something, but if we instead forget to whitelist something, our app yells will complain about us. ...and then we'll remember.

11.2.2 | SQL Injection

If you were a hacker, SQL injection is the act of making a web application execute SQL that you've written. By running your own SQL on a web application, you can create new records, update records to give yourself admin permissions, read sensitive data that you have no right to read (e.g. credit card numbers), or even destroy everything.

How is this possible?

Well, first of all, all the things listed above can easily be performed with SQL, so an adept hacker just needs to figure out the database schema to make them happen (with SQL).

Secondly, the means by which you would have this arbitrary SQL executed is by "injecting" SQL as raw text into some form input, query string parameter, etc and hope that the developer of the web application didn't bother to sanitize that text before trying to store it to the database.

Fortunately, Rails sanitizes input like this by default for arguments passed in calls like Erratum.new or Erratum.create, but there are other circumstances where we might use SQL fragments in ActiveRecord. When we do, we must be careful about how we produce the SQL text.

Specifically, something we should never write is anything like:

Chapter.where("title = #{params[:title]}")

Though we could easily have done Chapter.where(title: params[:title]) instead and been safe here, there are times when using a fragment of SQL is necessary.

The safe way of writing this line in Rails is like this:

Chapter.where(["title = ?", params[:title]])

If we use this syntax, Rails will sanitize the string from params[:title] and replace the ? in the SQL fragment with that sanitized value.

And we'll be good to go.

This is definitely something to read up on, but a little knowledge of this topic goes a long way in being mindful of what you place in your database and how.

11.2.3 | XSS

Cross-Site Scripting, commonly referred to as XSS, when treated as a security vulnerability is the act of injecting a script into a page which is then executed by the visitors of that site, particularly for a purpose that is malicious or unintended by the owner of the site.

We certainly put scripts into pages ourselves, but the issue with XSS is that the scripts are being injected into the page, unbeknownst to the owner of that site. Once injected, these scripts can do a great deal of damage, commonly by stealing the contents of session cookies and sending their values back to a server that can then use them to masquerade as the users that the sessions belong to. This can lead to illegitimate posting on social media sites, deletion of accounts, or even the compromise of bank accounts, depending on what kind of cookies were stolen.

So how do these scripts get injected into the page in the first place?

Again, Rails does us a favor and automatically HTML escapes all text we render in a view, which prevents scripts from being injected.

That is the rule, but the exception is that sometimes we have text representing HTML and want it rendered, not escaped.

We actually ran across a situation that could be vulnerable to an XSS attack ourselves in our project. Any idea where that might have been?

The answer is app/views/chapters/show.html.erb. To avoid the automatic HTML escaping we used raw @chapter.body for dropping the chapter body into the page. This could be quite dangerous, except that we are assuming that the admin for our application are not malicious.

If we wanted to use raw for text from normal users, we'd definitely want to parse the text and remove any <script> tags first.

Having said all of that, there are times when we actually want to include scripts from other domains. Examples of this would be using Google Analytics or using ajax.googleapis.com/ajax/libs/jquery/ to include jQuery on a page (as jquery.com itself does).

11.2.4 | HTTPS and SSL

HTTP Secure (HTTPS) is used to prevent others from spying on or messing with our site traffic. By configuring our server to use an SSL certificate, we can prove to users that our server is where it claims to be and encrypt our transmissions with clients.

HTTPS is generally useful for securing our traffic, but also required for certain things, like using Stripe in production.

You can read more about this specifically in relation to Heroku here.

11.2.5 | The Rails Session

As we saw earlier, we have access to the Rails' session cookie by way of the session variable in our controllers.

We used session to store the current user's User id in session[:user_id], which might seem dangerous.

Couldn't anyone find (or guess) an admin's ID and just put it inside of the session cookie to login as that admin?

They absolutely could, except for the way that Rails handles the session. Rails keeps track of the session data on the server and sends the client a very long and very random hexadecimal session ID to the client to be stored in a cookie.

You can check this out in every request to your local server in Dev Tools by looking in Network -> Headers -> Request Headers -> Cookie.

Rails can take this session ID from a session cookie that is passed in and use it to securely retreive the session data server-side.

11.3 | Performance

We're about to look through performance topics, but considering these things will be entirely futile in the end if you don't understand the metrics.

In terms of web applications, we ultimately end up dealing with three constraints: processing, storage, and network transfer.

The processing and network transfers are usually measured with units of time whereas storage is measured using some derivative of the byte. Becoming familiar with the length/size of these units is critical to understanding when something is fast and, perhaps more importantly, when something is slow.

We'll be talking more about this and more in the next chapter.

As for generally understanding computer performance, I highly recommend working doing a few projects in a lower-level language like C or even Assembler. Languages like these force the programmer to be aware of many of the different "moving parts" of a computer and in doing so will nurture a general (healthy) paranoia that "I'm doing this ineffciently".

A superbly well-written introduction to both these languages, as well as many other topics, can be found in Hacking: The Art of Exploitation, 2nd Edition.

11.3.1 | Database Indexing

We've already mentioned indexing our database several times, but now that we have a complete application, this is certainly something worth revisiting.

The first simple rule is to index all foreign keys. Rails helps us out with this, as we mentioned before, as using [attribute]:references in a scaffold generator will index the resulting column. If you can't use this form, remember to use something like [attribute_id]:integer:index to get the column indexed.

You can also add the index in the migration file by hand, but that's a pain.

That first rule actually falls under a greater, broader rule: index any column that you will frequently search.

Indexing columns does have its cost, but applying this rule can pay huge dividends when used appropriately.

11.3.2 | Caching

We've already done some primitive caching with instance variables and the ||= operator, but Rails helps further with an assortment of mechanisms to prevent unnecessary re-rendering of views or repeated trips to the database for the same data while in the production environment.

A good place to start learning about caching in Rails would be by reading this, another great Rails Guide.

When a Rails app has a cache hit (data is read from the cache, not the DB), we will see CACHE listed in the logs. The reason we haven't seen this in our server output yet is because this functionality is disabled by default in the development environment.

11.3.3 | Storing vs Processing

When receiving large or complicated data, think critically about how you should save it and how you should fetch it later.

Take our Markdown upload as an example. We receive the Markdown file as an upload, parse it, and save it inline with the request. In other words, the user has to wait for the whole process to complete before receiving a response from our server. Additionally, this is blocking, meaning the process that is running our application on the server cannot respond to any other requests while this is taking place.

That sounds terrible, why are we doing it that way?

We're okay to do this because these file uploads are relatively infrequent, since only admin can perform them. Furthermore, we don't really care about impressing the admin with faster response times.

We generally care about response times, but it's not worth the extra work here since this won't be impacting paying customers.

I guess that assumes that authors are not paying customers...

Well, I guess I'm writing this as a non-paying author and I don't care to be impressed with Markdown upload speeds.

So, if this were a problem impacting the bulk of our user base, how would we deal with it?

Well, one way would be to not store the HTML generated from the Markdown in the database at all. When a chapter was requested we could just grab the file, convert it to HTML, and drop it into the application layout.

Doing that would certainly cause the response for a chapter file upload to return much quicker, which works towards solving our problem, but in doing so we require that we convert the Markdown to HTML every time the chapter is requested. If that sounds like a ridiculous waste of processing power, it is.

So that's the nature of the dilemma: Do we process the data and store the result? Or do we just store the data and process it when we retrieve it?

Sometimes the data transformation we'll want to perform will be much less taxing than loading a sizable Markdown file into memory and converting it to HTML, in which case it may make sense to transform it for every request.

Even other times it will be convenient to store in a particular format because we will want to transform it into multiple, other formats depending on the circumstances.

But going back to our Markdown problem, what if we wanted the upload process to be faster and wanted chapter requests to stay as they are, what would we do?

In that case, there is actually something of a third option: we could perform the Markdown processing in a background job by placing it in a queue, using a gem like Resque.

With this method, the file is uploaded and the Markdown to HTML conversion is performed by a separate process whose sole job is to deal with these kind of things (as we tell it to). Meanwhile, having successfully queued the conversion of the Markdown as a background job, our controller action is free to respond to the client and report that all is well.

The conversion still takes as long as it would otherwise, but the user that uploaded the file doesn't have to wait for it to complete in order to get a response from the server. Furthermore, the process is then free to handle more incoming requests and other users are not blocked from using the application.

11.3.4 | Slow Queries

And one final reminder: don't blame ActiveRecord for the slowness of your database queries.

As much as it can do for us, it cannot optimize for speed if we write careless, wasteful code.

Two rules:

  1. be aware of what you're doing (e.g. don't load or write things twice when you don't need to)
  2. be aware of the SQL that's actually being run and understand what it's doing

11.3.5 | Much More

There are plenty of things left in Rails that we didn't have a chance to look at, like the Asset Pipeline, validations, and Internationalization (I18n).

To learn about these topics and more, I encourage you to read other books that are focused more on Rails specifically. There are plenty of great books out there for this purpose, but I've listed some of my favorites on the resources page.

But while we're still talking about Rails, let's look at a few final tricks for working with rails server.

Bonus!

First, let's see a couple of the options we can pass into rails server.

Since a web server is just another program, we can run as many of them as we want, but they can't all run on the same port.

I already have one running on port 3000 on my machine, let's see what happens if I try to fire up another one.

$ rails server
=> Booting Thin
=> Rails 3.2.8 application starting in development on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
>> Thin web server (v1.3.1 codename Triple Espresso)
>> Maximum connections set to 1024
>> Listening on 0.0.0.0:3000, CTRL+C to stop
Exiting
/home/brad/.rvm/gems/ruby-1.9.3-p194/gems/eventmachine-0.12.10/lib/eventmachine.rb:572:in `start_tcp_server': no acceptor (RuntimeError)
...

The error message here isn't particularly helpful, but after seeing start_tcp_server we could (correctly) deduce that the problem is a TCP issue. And (though we haven't mentioned it before) port 3000 is a TCP port, so this points to a port problem.

To avoid this error, all we have to do is tell rails server to start on a different port. And we can accomplish this with the -p flag:

$ rails server -p 4000
=> Booting Thin
=> Rails 3.2.8 application starting in development on http://0.0.0.0:4000
...

Now we can make requests to http://localhost:4000/ to access this instance of the application.

We can also specify that we want the application to run in a different environment using the -e flag:

$ rails s -e production -p 4000 
=> Booting Thin
=> Rails 3.2.8 application starting in production on http://0.0.0.0:4000
...

And look at that, we can even just use rails s to start our application server. It doesn't stop there though, we can use this format in other places too, like rails c instead of rails console and rails g instead of rails generate.

In fact, if we mix in a little bit of Bash, we can make this even shorter:

$ alias r=rails
$ r s -p 4000
=> Booting Thin
=> Rails 3.2.8 application starting in development on http://0.0.0.0:3000
...

alias is a Bash command and by passing it r=rails, we're telling it that we want it to run rails when we try to run a command named r.

For best results, place this alias in a file like ~/.bash_aliases (or whatever your operating system uses for this purpose).