This week I started Tealeaf Academy’s second, Rails-focused course and I’m pumped to now start building “real” applications that I can have live on the web. Throughout the course I’ll be building Postit!, a simplified Reddit clone with all functionality coded from scratch without the use of external libraries or gems. I’ll use the code from this app to illustrate my examples below.
In my post about my experiences with Tealeaf’s first course I took the approach of providing an overview of what was covered in the course, rather than covering any of the main concepts in any great detail. Given that the second and third courses focus on learning Rails inside out and back to front I’ll provide a lot more detail on each of the key topics covered so this will be useful to anyone taking this course, or indeed to anyone learning Rails generally. Converting my hurried notes into something more coherent should also help to sear this stuff into my brain.
To generate a new Rails app, you use the new application generator which is simply called with
rails new and the name for your app. For example:
$ rails new Postit!
creates a new app named Postit! with the files and folders you need to get started.
The default directory structure of a Rails app looks like this (adapted from RailsGuides):
|app/||This is the folder where you will work most of the time. It contains the controllers, models, views, helpers, mailers and assets for your application.|
|bin/||Contains the rails script that starts your app and can contain other scripts you use to setup, deploy or run your application.|
|config/||As the name suggests, this directory holds the configuration files for your application, including your database configuration (in database.yml), your Rails environment structure (environment.rb), and routing of incoming web requests (routes.rb). You can also specify environment-specific configurations for each of the three Rails environments (test, development and production) here.|
|db/||All database related files go into this folder including the schema and migrations. If you’re using SQLite, the database file (*.sqlite3) will be in this folder.|
|lib/||Extended modules for your application.|
|log/||Application log files.|
|public/||The only folder seen by the world as-is. Contains static files and compiled assets.|
|test/||Files for testing your application.|
|tmp/||Temporary files (like cache, pid, and session files).|
|vendor/||Libraries provided by third-party vendors (like security libraries or database utilities beyond the basic Rails distribution) go here.|
|Gemfile, Gemfile.lock||These files allow you to specify what gem dependencies are needed for your application. These files are used by the Bundler gem.|
|Rakefile||Handles all the Rake tasks inside your application.|
|README||This is one of the most important files in your application as it provides some basic detail about your app to others, such as what it does and how to set it up. It’s also displayed when users visit your app’s repository on GitHub.|
Rails uses the model-view-controller (MVC) architectural pattern. This pattern divides an application into three interconnected parts which separates the logic of the application from the rest of the user interface.
The controller receives requests from the router and connects the model with the view – it processes the data from the model and then passes this onto the view. The view is then rendered and displayed in the user’s browser.
The model represents the information and the data from the database. It is independent from the database and validates data before it is saved to the database.
The view is what the user sees. It requests information from the model that it uses to generate an output representation to the user. Inside the view you will find (most of the time) HTML with embedded Ruby code. In Rails, views are implemented using ERb (Embedded Ruby) by default.
The router is at the front door of your application. When a request is received, the router uses the HTTP verb (such as GET or POST), URL and parameters of the request to determine where to route it and then routes this to the appropriate controller and action - for example, with a Posts controller in your app, a request to localhost:3000/posts will be directed to the index action of the Posts controller by default. Once the request is routed to the controller, the controller can either render a view (the default action) or redirect the request.
The routing table for your app can be viewed by running
rake routes in the console or at
Routes for your app are configured in
config/routes.rb. Rails provides a resources helper method which can be called in your routes file to generate the required routes automatically.
In the case of my Postit! app, the code:
PostitTemplate::Application.routes.draw do resources :posts end
will create routes for the seven default actions for the Posts controller (index, create, new, edit, show, update, and destroy).
The resulting routing table looks like this:
Prefix Verb URI Pattern Controller#Action root GET / posts#index posts GET /posts(.:format) posts#index POST /posts(.:format) posts#create new_post GET /posts/new(.:format) posts#new edit_post GET /posts/:id/edit(.:format) posts#edit post GET /posts/:id(.:format) posts#show PATCH /posts/:id(.:format) posts#update PUT /posts/:id(.:format) posts#update DELETE /posts/:id(.:format) posts#destroy
In the Postit! app I want to prevent users deleting posts. To achieve this, the route to the destroy action of the Posts controller needs to be removed. This can be achieved by adding
except: :destroy to the call to the resources helper:
PostitTemplate::Application.routes.draw do resources :posts, except: :destroy end
You can about Rails routing in lot more detail at The Odin Project.
ActiveRecord is the ORM (Object Relational Mapping) library used in Rails applications by default. It is the Model in MVC, which is the layer responsible for representing business data and logic. ActiveRecord simplifies the use of databases in Rails applications by mapping each row of the database to an object and allowing you to create or retrieve data from your database in an object-oriented fashion without having to write complex SQL statements. For example, to retrieve an array of all User objects from your database you simply use
ActiveRecord models can be connected through associations, which enable you to tie objects in different models together to express relationships like “a Comment belongs to a Commenter”.
Rails supports six types of associations:
The primary associations used between the models in the Postit! app are has_many and has_many :through:
A has_many association indicates a one-to-many connection with another model. In the Postit! app, a User has many Posts and Comments:
class User < ActiveRecord::Base has_many :posts has_many :comments end
The has_many :through association allows you to connect two models through a third model (a “join model”). In the case of the Postit! app, the Post and Category models are connected through the PostCategory model:
class Post < ActiveRecord::Base has_many :post_categories has_many :categories, through: :post_categories end