Many of the ideas here will probably be familiar, if only in name, but let's make sure we're on the same page.

3.1 | The Browser

We've certainly already used the browser, but it's worth taking a look at some of the details of what's going on in the background. To do this, we'll just be looking around Dev Tools a little more, but keep in mind that Dev Tools simply serves as a means of peeking into the inner workings of the browser.

We'll only be looking at the Network and Elements tabs of Dev Tools, as they are two incredibly critical features.

This is just my opinion, so feel free to look into the others, but Console along with the two I just mentioned are the ones I personally couldn't live without.

And we've already seen plenty of Console while learning all about JavaScript.

Before we move on to the specific tabs, it should be noted that the first three icons along the bottom from the very left remain constant regardless of what tab you're on. They look like this:

Chrome Dev Tool Icons

and, in order from left to right, they will:

  1. dock/undock Dev Tools with the main browser window
  2. show the JavaScript console underneath the current view (disabled on Console)
  3. allows inspect element in the page by hover and click

Network tab

If you're on the Network tab and load a page, you'll see every file request that the browser makes in order to completely render the page.

The term "file request" here can be something of a misnomer as we'll soon see when we talk about web applications. Regardless, each "file request" is an HTTP request that contains something resembling file contents as the response body.

You'll see that All at the bottom is selected by default to show you every single request that is made. You will also see other choices to narrow down what is shown:

Name Meaning
Documents HTML documents
Stylesheets CSS
Images ... um, images
Scripts JavaScript
XHR more on this when we learn about Ajax
Fonts ... you guessed it, fonts
Websockets out of scope for us
Other anything else

Take special notice that Images have their own tab here. This means that images are each fetched through their own HTTP requests.

Fonts is something a bit new. There have always been a number of fonts that will work in any web browser and do not have to be downloaded for every use, but Fonts here is in reference to fonts like Google Web Fonts.

To the left of these selections, you'll see three more icons. These icons look like this:

Dev Tools Network Icons

and, left to right, they will:

  1. shrink/grow the display size and contents of the request data above
  2. persist the request data above even if you navigate to another page (or reload the current one)
  3. clear the request data above

The second of these can be particularly useful if certain requests clear out before you can get at them.

Ok, now that we've looked at the controls, let's go over the request themselves. From left to right:

  1. Name/Path - the name of the file / path to the file
  2. Method - HTTP request method (a.k.a. HTTP verb) used for the request
  3. Status/Text - the HTTP status code from the response / the text equivalent for that code
  4. Type - the file type of the response body (e.g. 'text/plain', 'image/gif'), also known as "Content-Type" or "MIME type"
  5. Initiator - points to what initiated the request (e.g. redirect from a certain path)
  6. Size/Content - HTTP response size / response body size
  7. Time/Latency - how long the request took

And don't forget that if you click on a given request you can also view:

  • the request and response headers
  • the response body
  • the request/response cookies

The Browser Cache

If you've visited a given page before, you may notice some requests have "(from cache)" in the "Size/Content" column.

What this means is that the browser used a resource that it already had cached locally and did not actually request the resource from the server. This process is dictated by the headers like Cache-Control and Expires.

You can learn more about caching here.

Keep in mind if you've changed something server-side and aren't seeing the change in the browser, there could be a caching issue. That is, it could be the case that the browser has cached, say, an image that it's previously requested and your changes to the image aren't showing up because the browser is just fetching the image from the cache instead of requesting it from the server.

From a browser standpoint, the solution to this is clear out your cache. In Chrome simply pressing CTRL SHIFT DELETE will take you to a new tab that will let you clear all kinds of browsing data, including the cache. Make sure only Empty the cache is checked (unless you want to destroy something else) and then press the Clear browsing data button to blow away anything you have cached.

Notice too that there is a drop-down menu that will give you more granular control of how far back in time things are deleted.

Furthermore, you can also Delete cookies and other site and plug-in data. This can be equally handy if you want to get rid of cookies in the same manner.

A good way to avoid this problem altogether is to just use an "incognito window" to view your site instead. To open one, just press CTRL SHIFT n.

When this window opens, it won't bring any locally persisted data, like cookies, with it.

Elements tab

Switching over to the Elements tab, we're greeted by an easily readable, collapsible representation of the HTML for the current page. We can edit the HTML in this view and our changes will be applied to the page. Inversely, as changes are made to the page, this view will be updated dynamically.

How would changes be made to the page?

By way of DOM manipulation (like we saw last chapter), in our case using jQuery.

Here we can click the arrow to the left of any given element in the Elements view to expand it and see its child elements and so on. ...and so on.

We can also edit existing elements in the page. To test this out, just find some element in the Elements view that contains text, like a <p>, double-click its text contents, type in something of your own, and hit ENTER. After that, you'll see the text you typed on the page.

My preferred way of doing would be to simply right-click a block of text that I wanted to mess with and then click Inspect Element from the context menu. This will drill down in the HTML and select it the proper element for you in the Element tab view.

Just as you can double-click to change an element's content, you can also double-click a tag to change the tag type or double-click an attribute to change it's value. You can even add new attributes to an element by clicking inside its opening tag.

And as we saw earlier, if there is a path or URL to a file (such as image), that path/URL will display as a link which you can click to view the file in more detail.

As you click on elements more deeply nested in the document, the bottom of Dev Tools will keep a detailed trail of CSS selectors from the currently selected element (on the far right) all the way up to html (far left). Clicking on any of these selectors will select that element in the Elements view.

Speaking of CSS selectors, if you look to the right side of the Elements view, you should see something titled "Styles" expanded by default. Inside, you'll see lines of CSS which are proceeded by checkboxes when you hover over them with your mouse. Unchecking one of these boxes will disable the CSS for the corresponding line. Checking it will re-enable that CSS.

disabling a line of CSS from the CSS sidebar

"You're playing God!"

"Somebody has to!"

- The Man with Two Brains

Single-clicking a CSS property or value will allow you to edit it, just as we were editing HTML earlier. After you hit ENTER, the CSS changes you made will be applied to the page.

adding a line of CSS to be applied to the current element

I usually click the property and then hit TAB to jump over to the value, the next property, its value, and so on.

As you type, Dev Tools will try to autocomplete the property or value you're in the middle of. If it guesses correctly, you can hit RIGHT to have it filled in for you.

If you don't see a selector you want, hitting the + to the right of Styles will make a new one for you with an empty declaration (an empty {}).

And remember how the "C" in "CSS" is for "Cascading"?

Well, you can even see CSS definitions that were cascaded over by later definitions if you scroll down. They'll be the ones that are struckthrough as they are no longer applied to the elements.

That is, they look like this.

And be sure to note that in addition to showing which styles are active and which are not, we can also see the file and line number in that file where the styles came from.

Below we can see from bootstrap_and_overrides.css:853 that the styles shown come from line 853 of a file named bootstrap_and_overrides.css:

CSS styles with filename and line number

And while we're here, take a look at Computed Style.

CSS Computed Style

This is an exhaustive list of the resulting styles applied to the element.

View source

Using the Elements tab is really useful, but if you ever want a quick way to see the original HTML source for the page you're viewing, simply use CTRL + U.

3.2 | Web Server

You'll recall, we've already touched on the idea of "servers" being physical machines that run things like "web server" software, but let's take a deeper look at that.

Just as our client machine needs a client application (a browser in our examples) to make HTTP requests, a server machine needs to be running a web server in order to react to incoming HTTP and to send HTTP responses.

Initially, web servers would simply receive an HTTP request for a file and send back an HTTP response containing the file in the body. The file would be one that was stored on the server machine's local filesystem (i.e. a file saved to the hard drive) and would be sent back to the client without any manipulation, just inserted into the HTTP response as the body.

If a client were to request the path /foo/bar.html from one of these web servers, the web server would simply get the file from the proper location on its file system, say, /{appropriate_path_prefix}/foo/bar.html, stuff that file's contents into the HTTP response body, set Content-Type in the HTTP header to text/html, and send it all back to the client.

Notice here that there is no logic or data transformation taking place server-side, that this kind of simple web server responds to the client with a static file.

A distinction to draw here is that what we have described thus far is a web server and not a web application. The server knows nothing of the client, it just hands files back over HTTP as it is asked.

There are all kinds of web servers available but some popular examples would be Apache, lighttpd, and Ngnix.

You're bound to see these mentioned elsewhere, but we won't be talking anymore about these specifically. The reason for this is that there are a number of web servers written in Ruby that work great with Rails, including the one we'll be using: Thin.

We'll take a look at Thin later when we get into the tools available to us through the Ruby community.

While these web servers are a software component of a web application running in production on a remote server, we can also run them locally for development and testing purposes.

The terms "production server" and "staging server" usually refer to dedicated servers, often running remotely. The production server will be the machine that the site is actually served from, while the staging server will be a server that is configured similarly to the production server, but used instead to make sure everything works properly before pushing changes to production.

Additionally, it's important to note that we can run instances of these web servers on our local machines to see our changes as we develop and for testing purposes.

In fact, I have two such instances running on this laptop at the moment.

More on all of this later, but the terminology is helpful to know.

3.3 | Database (DB)

READERS - Sam - Please proof-read the crap out of this.

You've almost certainly heard the terms "database" before, but you might not know what it actually means.

I sure didn't when I came to Rails.

Throughout this book we'll be using a couple different Relational Database Management Systems (RDBMS). Some common examples of these are:

  • SQLite
  • PostgreSQL
  • MySQL

So a DBMS will manage a database for us, but what is a database?

In systems like these, a database is a means of persisting data in an organized fashion using tables. These tables have columns and rows.

Tables are pre-defined structures; their columns are declared in advance by name and data type.

Tables are populated with data by adding new rows to them and existing rows can retrieved en masse or by querying for specific values.

The data we end up with that was stored as a row in a database will be referred to as a "record" once we're working in Rails.

To make this a little more tangible, let's imagine we wanted to keep track of people and their home states.

A database table to handle this could have the following columns:

full_name (string) home_state (string)

And a row representing myself would look like this:

full_name (string) home_state (string)
Brad Chase Ohio

Why DB?

Why would someone want to use a database? Why can't data just be saved in files?

The short answer: databases are faster and more reliable.

This is a huge topic all on its own, but suffice it to say that databases are well suited for consistently storing information and for looking up stored data quickly.

Furthermore, this can all be done programmatically.

SQL

SQL stands for "Structured Query Language" and is a language used to do things like create and drop tables in a database; insert rows in and delete rows from a table; and query a database to retrieve data where certain requirements are met.

This is another enormous topic that cannot be done justice within this book, but fortunately for us, ActiveRecord (a component of Rails) is going to take care of writing SQL for us. This is great news if you, like me, discover that you don't particularly love writing SQL, but it is no excuse not to understand SQL and its best practices. Though Rails will be writing SQL for us, we will still dictate what it will be trying to accomplish and how the tables are set up. The onus of writing performant code in regards to database queries is on us.

Let's run through some SQL syntax by implementing our name/home state example from above.

You won't need to type along with this tutorial, but everything below ran properly in SQLite3.

First, let's create a table named people to store data in:

CREATE TABLE people(
  full_name VAR_CHAR(30),
  home_state VAR_CHAR(20)
);

Next, we'll insert my information into the table:

INSERT INTO people
    (full_name, home_state)
  VALUES
    ('Brad Chase', 'Michigan');

Whoa, that home state definitely isn't right. Let's update it:

UPDATE people
  SET home_state = 'Ohio'
  WHERE full_name = 'Brad Chase';

We can then grab every column of every row in the people table like so:

SELECT * FROM people;

Or every column of every row that has a full_name of 'Brad Chase'table like so:

SELECT * 
  FROM people
  WHERE full_name = 'Brad Chase';

There's also an equivalent syntax for this which see used later by Rails in the Rails console:

SELECT "people".*
  FROM "people"
  WHERE "people"."full_name" = "Brad Chase";

And, of course, we can also blow my record away:

DELETE FROM people 
  WHERE full_name = 'Brad Chase';

You'll see the SQL that Rails generates in the output of the Rails console when we get around to giving it a try, but you won't be needing to write any complete SQL statements yourself (at least not for the duration of this book).

Indexing

In terms of speed for lookups, a critical factor involves the column being checked with the WHERE, specifically whether or not that column is indexed.

We won't be covering the mechanisms that make this work, but know that it can quicken lookups that test a certain column at the expense of storing more data on disk.

It's been said that any column that you do frequent WHERE checks on should be indexed.

Primary keys

Thus far we've only looked up a specific row by using a WHERE to check for a specific full_name. Though there certainly are cases that require this, often times it's easier to pass around a unique identifier for a given record and instead use that to SELECT the proper row.

In relational databases, this unique identifier is referred to as a primary key. In Rails, primary keys will be represented by an integer column named id that is added automatically to each table Rails helps to create.

If we had Rails help create the earlier table for us, it would look something like this:

CREATE TABLE people(
  id INT,
  full_name VAR_CHAR(30),
  home_state VAR_CHAR(20),
  PRIMARY KEY (id)
);

CREATE UNIQUE INDEX index_id_on_people
  ON people (id);

Notice here that Rails would automatically apply a unique index to the primary key, since they are commonly used to fetch a particular row using a WHERE.

Then, given that the table is completely new, if we used Rails to add my record to the database with the data from before, it would automatically be given an id of 1. The SQL would look something like this:

INSERT INTO people
    (id, full_name, home_state)
  VALUES
    (1, 'Brad Chase', 'Ohio');

Which would allow for access to the row later like so:

SELECT *
  FROM people
  WHERE id = 1;

Foreign keys

If you've thought critically about our example of storing people's home states, you may have noticed that if you had two people with a home_state of 'Ohio', the data 'Ohio' would be redundantly stored twice. In fact, there's really no need to actually record the string Ohio for both, what we really want is to associate both with a given state.

Enter foreign keys.

Foreign keys reference the primary key of another a row of, commonly in another table. In Rails, this means that they reference an id somewhere.

Let's start over and create a table for all of the states as well as a people table that will reference it.

CREATE TABLE states(
  id INT,
  name VAR_CHAR(30),
  PRIMARY KEY (id);
);

CREATE UNIQUE INDEX index_id_on_states
  ON states (id);

CREATE TABLE people(
  id INT,
  full_name VAR_CHAR(30),
  home_state_id INT,
  PRIMARY KEY (id);
);

CREATE UNIQUE INDEX index_id_on_people
  ON people (id);

Now let's say we have a people table populated like this:

id (integer) full_name (string) home_state_id (integer)
1 Brad Chase Ohio

And a states table like this:

id (integer) name (string)
17 Ohio

This way, if we have a row from people in hand, we can look up their home state name using that row's home_state_id. Inversely, if we have a row from states and want to gather all the rows for people who have it as a home state.

We'll be looking more at relationships like these when we talk about Rails models.

One last note on foreign keys: it's usually recommended they be indexed. We'll look more at this later on after we've worked on our Rails app.

Transactions

"Transactions are protective blocks where SQL statements are only permanent if they can all succeed as one atomic action. The classic example is a transfer between two accounts where you can only have a deposit if the withdrawal succeeded and vice versa." - api.rubyonrails.org

Rails will naturally wrap some things in an SQL transaction, but it is also possible for us to use transactions ourselves.

...we just won't.

We won't be dealing explicitly with SQL transactions in this book, but we might see the output from a couple of them as we go.

NoSQL

It's worth mentioning here that there are a growing number of "NoSQL" database solutions such as MonogoDB and CouchDB that do not use SQL and that do not adhere to many of the ideas we've discussed above.

Systems like these have their benefits and can easily be used with Rails now, but we won't be covering them in this book.

3.4 | Version Control

So let's say you have a project you've been working on for a while that is running perfectly. You then decide that you want to implement a new feature.

You make your changes, save all the files, check to make sure things aren't broken, and call it a night.

The next day you fire everything back up and you notice that there are actually a lot of things broken, you just didn't notice before. You would normally just undo your changes, but you already closed out your editor earlier and that's no longer an option.

Wouldn't it be fantastic to just change your project back to a state where everything was functioning properly?

Hmm.

Imagine that you're working remotely on the same project with another developer. There's a main JavaScript file that gets changed a lot and you both change the same line to do two new, different things. If you both had the file open and saved it out to some remote location, the changes saved first would be blown away. What's worse, the person whose changes eventually ended up in the file wouldn't even know that they just hosed the other's work.

Instead of this setup, wouldn't you want to take both changes into consideration and end up with a line that accomplished both changes? Not just the latest change?

Uh, yeah.

The solution to these problems (and more) is what is called version control.

You may also hear this concept referred to as revision control or source control.

Programs that offer this functionality are called Version Control Systems (VCS). Common examples of these are Subversion, Mercurial, and Git.

Mercurial is cleverly abbreviated to ["Hg"](http://en.wikipedia.org/wiki/Mercury_(element) and Subversion is often cut down to just "SVN".

Though all of these are used extensively, we will be looking exclusively at Git, because the Ruby community strongly favors it over the others.

More specifically, Git is a distributed VCS. This means a series of things, but what we need to understand about it is that it allows developers to work locally on a codebase, versioning their changes as they go, and then provides a mechanism to push their changes up to a remote repository where others can pull those changes down.

When there are conflicts between a local codebase and code that has just been pulled down, Git allows the two to be merged by displaying the file's differences and then letting the developer decide which changes to keep.

Because of these features, Git makes it easy to share changes to the codebase among developers, whether their across the room or on the other side of the globe. And even if you're working alone, Git is helpful for versioning and backing up your changes as you go.

While writing this book I backed up both the application code and the chapter text using Git.

We'll be taking a hands-on look at Git later when we start talking about our tools.