🤯 50% Off! 700+ courses, assessments, and books

Learn Ruby on Rails: the Ultimate Beginner’s Tutorial

    Patrick Lenz

    Database Tables

    We’ve already created a database for each of our environments (development, testing, production), but there aren’t any tables in those databases yet. Tables are the containers within a database that store our data in a structured manner, and they’re made up of rows and columns. The rows map to individual objects, and the columns map to the attributes of those objects. The collection of all the tables in a database, and the relationships between those tables, is called the database schema. An example of a table is shown in Figure 4.5.

    Figure 4.5. The structure of a typical database table, including rows and columns

    In Rails, the naming of Ruby classes and database tables follows an intuitive pattern: if we have a table called stories that consists of five rows, then that table will store the data for five Story objects. The nice thing about the mapping between classes and tables is that it’s not something that you need to write code to achieve — it just happens, because ActiveRecord infers the name of the table from the name of the class. Note that the name of our class in Ruby is a singular noun (Story), but the name of the table is plural (stories).

    This relationship makes sense if you think about it: when we refer to a Story object in Ruby, we’re dealing with a single story. But the MySQL table holds a multitude of stories, so its name should be plural. While it’s possible to override these conventions (as is sometimes necessary when dealing with legacy databases), it’s much easier to adhere to them.

    The close relationship between tables and objects extends even further: if our stories table were to have a link column, as our example in Figure 4.5 does, then the data in this column would automatically be mapped to the link attribute in a Story object. And adding a new column to a table would cause an attribute of the same name to become available in all of that table’s corresponding objects.

    So, let’s create some tables to hold the stories we create.

    For the time being, we’ll create a table using the old-fashioned approach of entering SQL into the MySQL command line. You could type out the following SQL commands, although I acknowledge that typing out SQL isn’t much fun. Instead, I’d encourage you to download the following script from the code archive, and copy and paste it straight into your MySQL console.

    Example 4.3. 03-create-stories-table.sql
    USE shovell_development;
    CREATE TABLE `stories` (
    `id` int(11) NOT NULL auto_increment,
    `name` varchar(255) default NULL,
    `link` varchar(255) default NULL,
    PRIMARY KEY (`id`)

    You needn’t worry about remembering these SQL commands to use in your own projects; instead, take heart in knowing that in Chapter 5, Models, Views, and Controllers, we’ll look at something called migrations, which are special Ruby classes that we can write to create database tables for our application without using any SQL at all.

    Using the Rails Console

    Now that we have our stories table in place, let’s exit the MySQL console and open up a Rails console. A Rails console is just like the interactive Ruby console (irb) that we used in Chapter 3, Introducing Ruby, but with one key difference: in a Rails console, you have access to all of the environment variables and classes that are available to your application while it is running. These are not available from within a standard irb console.

    To enter a Rails console, change to your shovell folder, and enter the command ruby script/console, as shown below. The >> prompt is ready to accept your commands:

    $ cd shovell
    $ ruby script/console
    Loading development environment.

    Saving an Object

    To start using ActiveRecord, simply define a class that inherits from the ActiveRecord::Base class. (We touched on the :: operator very briefly in Chapter 3, Introducing Ruby, where we used it to refer to constants. It can also be used to refer to classes that exist within a module, which is what we’re doing here.) Flip back to the section on object oriented programming (OOP) in Chapter 3, Introducing Ruby if you need a refresher on inheritance.

    Consider the following code snippet:

    class Story < ActiveRecord::Base

    These two lines of code define a seemingly empty class called Story. However, this class is far from empty, as we’ll soon see.

    From the Rails console, let’s create this Story class, and an instance of the class called story, by entering these commands:

    >> class Story < ActiveRecord::Base; end
    => nil
    >> story = Story.new
    => #<Story:0x2642900 @attributes={"link"=>nil, "name"=>nil},
    >> story.class
    => Story

    As you can see, the syntax for creating a new ActiveRecord object is identical to the syntax we used to create other Ruby objects in Chapter 3, Introducing Ruby. At this point, we’ve created a new Story object. However, this object exists in memory only — we haven’t stored it in our database yet.

    We can confirm the fact that it hasn’t been saved yet by checking the value of the new_record attribute, using the object’s accessor method:

    >> story.new_record?
    => true

    Because the object has not been saved yet, it will be lost when we exit the Rails console. To save it to the database, we need to invoke the object’s save method:

    >> story.save
    => true

    Now that we’ve saved our object (a return value of true indicates that the save method was successful) our story is no longer a new record. It’s even been assigned a unique ID, as shown below:

    >> story.new_record?
    => false
    >> story.id
    => 1

    Defining Relationships Between Objects

    As well as the basic functionality that we’ve just seen, ActiveRecord makes the process of defining relationships (or associations) between objects as easy as possible. Of course, it’s possible with some database servers to define such relationships entirely within the database schema. However, in order to put ActiveRecord through its paces, let’s look at the way it defines these relationships within Rails.

    Object relationships can be defined in a variety of ways; the main difference between these relationships is the number of records that are specified in the relationship. The primary types of database associations are:

    • one-to-one associations
    • one-to-many associations
    • many-to-many associations

    Let’s look at some examples of each of these associations. Feel free to type them into the Rails console if you like, for practice. Remember that your class definitions won’t be saved, though — I’ll show you how to define associations in a file later.

    Suppose our application has the following associations:

    An Author can have one Weblog:

    class Author < ActiveRecord::Base
    has_one :weblog

    An Author can submit many Stories:

    class Author < ActiveRecord::Base
    has_many :stories

    A Story belongs to an Author:

    class Story < ActiveRecord::Base
    belongs_to :author

    A Story has, and belongs to, many different Topics:

    class Story < ActiveRecord::Base
    has_and_belongs_to_many :topics
    class Topic < ActiveRecord::Base
    has_and_belongs_to_many :stories

    You’re no doubt growing tired of typing class definitions into a console, only to have them disappear the moment you exit the console. For this reason, we won’t go any further with the associations between our objects — we’ll delve into the ActiveRecord module in more detail in Chapter 5, Models, Views, and Controllers.

    The ActionPack Module

    ActionPack is the name of the library that contains the view and controller parts of the MVC architecture. Unlike the ActiveRecord module, these modules are a little more intuitively named: ActionController and ActionView.

    Exploring application logic and presentation logic on the command line doesn’t make a whole lot of sense (views and controllers are designed to interact with a web browser, after all!). Instead, I’ll just give you a brief overview of the ActionPack components, and we’ll cover the hands-on stuff in Chapter 5, Models, Views, and Controllers.

    ActionController (the Controller)

    The controller handles the application logic of your program, acting as a glue between the application’s data, the presentation layer, and the web browser. In this role, a controller performs a number of tasks, including:

    • deciding how to handle a particular request (for example, whether to render a full page or just one part of it)
    • retrieving data from the model to be passed to the view
    • gathering information from a browser request, and using it to create or update data in the model

    When we introduced the MVC diagram in Figure 4.3 earlier in this chapter, it might not have occurred to you that a Rails application can consist of a number of different controllers. Well, it can! Each controller is responsible for a specific part of the application.

    For our Shovell application, we’ll create:

    • one controller for displaying story links, which we’ll name StoryController
    • another controller for handling user authentication, called AccountController

    Both controllers will inherit from the ActionController::Base class, but they’ll have different functionality, implemented as instance methods. (There will actually be an intermediate class between this class and the ActionController::Base class; we’ll cover the creation of the StoryController class in more detail in Chapter 5, Models, Views, and Controllers. However, this doesn’t change the fact that ActionController::Base is the base class from which every controller inherits. Here’s a sample class definition for the StoryController class:

    class StoryController < ActionController::Base
    def index
    def show

    This simple class definition sets up our StoryController with two empty methods — the index method, and the show method — both of which we’ll expand upon in later chapters.

    Naming Classes and Files

    You’ll have noticed by now that the names of classes and files follow different conventions:

    • Class names are written in CamelCase (each word beginning with a capital letter, with no spaces between words).
    • Filenames are written in lowercase, with underscores separating each word.

    This is important! If this convention is not followed, Rails will have a hard time locating your files. Luckily, you won’t need to name your files manually very often, if ever, as you’ll see when we look at generated code in Chapter 5, Models, Views, and Controllers.

    Each controller resides in its own Ruby file (with a .rb extension), which lives within the app/controllers directory. The StoryController class that we just defined, for example, would live in the file app/controllers/story_controller.rb.

    ActionView (the View)

    As we discussed earlier, one of the principles of MVC is that a view should contain presentation logic only. This means that the code in a view should only perform actions that relate to displaying pages in the application — none of the code in a view should perform any complicated application logic, nor should it store or retrieve any data from the database. In Rails, everything that is sent to the web browser is handled by a view.

    Predictably, views are stored in the app/views folder of our application.

    A view need not actually contain any Ruby code at all — it may be that one of your views is a simple HTML file. However, it’s more likely that your views will contain a combination of HTML and Ruby code, making the page more dynamic. The Ruby code is embedded in HTML using embedded Ruby (ERb) syntax.

    ERb is similar to PHP or JSP, in that it allows server-side code to be scattered throughout an HTML file by wrapping that code in special tags. For example, in PHP you might do something like this:

    <strong><?php echo 'Hello World from PHP!' ?></strong>

    The equivalent in ERb would be the following:

    <strong><%= 'Hello World from Ruby!' %></strong>

    There are two forms of the ERb tag pair: one that includes the equal sign, and one that does not:

    <%= ... %>

    This tag pair is for regular output. The output of a Ruby expression between these tags will be displayed in the browser.

    <% ... %>

    This tag pair is for code that is not intended to be displayed, such as calculations, loops, or variable assignments.

    An example of each is shown below:

    <%= 'This line is displayed in the browser' %>
    <% 'This line executes silently, without displaying any output' %>

    You can place any Ruby code — be it simple or complex — between these tags.

    Creating an instance of a view is a little different to that of a model or a controller. While ActionView::Base (the parent class for all views) is one of the base classes for views in Rails, the instantiation of a view is handled completely by the ActionView module. The only thing a Rails developer needs to modify is the template, which is the file that contains the presentation code for the view. As you might have guessed, these templates are stored in the app/views folder.

    As with most things in Rails, a strict convention applies to the naming and storage of template files:

    • A template has a one-to-one mapping to the action (method) of a controller. The name of the template file matches the name of the action to which it maps.
    • The folder that stores the template is named after the controller.
    • The extension of the template file varies on the basis of the template’s type. By default there are three types of template in Rails:
      • rhtml – This is the extension for standard HTML templates that are sprinkled with ERb tags.
      • rxml – This extension is used for templates that output XML (for example, to generate RSS feeds for your application).
      • rjs – This extension is used for templates that return JavaScript instructions. This type of template might be used, for example, to modify an existing page (via Ajax) to update the contents of a <div> tag.

    This convention may sound complicated, but it’s actually quite intuitive. For example, consider the StoryController class that we defined earlier. Invoking the read method for this controller would, by default, attempt to display the ActionView template that lived in the app/views/story directory. Assuming the page was a standard HTML page (containing some ERb code), the name of this template would be read.rhtml.

    Rails also comes with special templates such as layouts and partials. Layouts are templates that control the global layout of an application, such as structures that remain unchanged between pages (the primary navigation menu, for instance). Partials are special subtemplates (the result of a template being split into separate files, such as a secondary navigation menu or a form) that can be used multiple times within the application. We’ll cover both layouts and partials in Chapter 7, Ajax and Web 2.0.

    Communication between controllers and views occurs via instance variables that are populated from within the controller’s action. Let’s expand upon our sample StoryController class to illustrate this point (there’s no need to type any of this out just yet):

    class StoryController < ActionController::Base
    def index
    @variable = 'Value being passed to a view'

    As you can see, the instance variable @variable is being assigned a string value within the controller’s action. Through the magic of ActionView, this variable can now be referenced directly from the corresponding view, as shown in the code below:

    <p>The instance variable @variable contains: <%= @variable %></p>

    This approach allows more complex computations to be performed outside the view (remember, it should only contain presentational logic), leaving the view to display just the end result of the computation.

    Rails also provides access to special containers, such as the params and session hashes. These contain information including the current page request and the user’s session. We’ll make use of these hashes in the chapters that follow.

    Go to page: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10