Why Ruby on Rails Is Still Worth Your While as a Developer

What are the basic reasons a developer might choose Ruby on Rails over any of the newer frameworks, such as Next.js or Vue? There are plenty of choices today; recently I looked at Eleventy, for example, which specializes in static websites using the Jamstack model.
The main attraction of Rails is indeed those rails — the loving embrace of opinionated software. Because Rails mirrors the development of agile itself, you will find a workflow (and several variants) mapped out for you. The whole concept of devs blogging about development is very much a Rails thing. Just look at the wealth of material on, for example, rspec on the topic of behaviour-driven development.
I remember in a code jam using Devise for user authentication over 10 years ago. It’s designed to use with Rails and is still available and managed. From a business perspective, this one Rails solution might represent a stronger assurance of quality than those available from other frameworks, whose creators were still in kindergarten that long ago.
Even if your final destination is elsewhere, you can do a lot worse than start your full-stack life with Rails. Strong advocates for other frameworks may also have started with Rails in the past (that’s certainly the case with the creators of Remix).
Continuing Our Rails Config
In our last post, in which I showed you how to do a “full fat install” of Ruby on Rails, we were just getting into some object relational mapping (ORM). First we installed Ruby, Rails and sqlite3. We wrote a route, with a controller, and started the server. Then we created a model and our first migration (below), which is the description of a record. We are following on from this Rails guide.
1 2 3 4 5 6 7 8 9 |
class CreateArticles < ActiveRecord::Migration[7.1] def change create_table :articles do |t| t.string :title t.text :body t.timestamps end end end |
Why is it called a migration? Does it involve birds or border walls? A migration is a reference to a version of a schema or the changes to it. When we update this, we migrate from one version to another. I think the name has stuck precisely because it is slightly off key, yet memorable.
We will get an auto-incrementing primary key for free when we create_table, so all that matters are the columns, title and body we helped define earlier for the model, when we called the generator.
Before we go on, you might have noticed that in the previous post I never configured the database. Now, sqlite is “zero configuration,” which, needless to say, will not match what you want for production. It does mean, however, that I don’t need credentials.
We can see database configuration in two places. The first is config/database.yml.
1 2 3 4 5 6 7 8 |
default: &default adapter: sqlite3 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> timeout: 5000 development: <<: *default database: storage/development.sqlite3 |
The other place is in the shell’s environment variables. The above confirms that sqlite3 will be used. If we really needed credentials, they would have to be referenced here.
Now that we have confirmed the database can probably hear us, lets run that first migration:
Cool, but what exactly did that do? Well, wisely the guide suggests that we plunge into the Rails console. This is like the live Ruby console, irb, but for Rails, and it groks the project’s Ruby source. Note how the completion already knows about our Article model, and the ArticlesController:
I know I can ask the model for all the existing Article objects, even though there should not be any as yet:
This clearly references the appropriate SQL, and believes the schema for the articles table is available. In which case, we can create an article and it should pop it in the table:
We can see how the object, once saved, is inserted via SQL into the table. The console is a good way to demystify ActiveRecord. But we are here to make a website, so let’s get back to the project source.
When we hit our one route, we want to fetch all the articles and then let the view show them all. This is the typical Model-View-Controller (MVC) flow; the data is in the model, the controller intercepts the REST request defined in the route, then the view shows the required data.
So the controller (i.e. app/controllers/articles_controller.rb) needs to load the articles:
1 2 3 4 5 |
class ArticlesController < ApplicationController def index @articles = Article.all end end |
So, @articles
represents a local variable, but one that the view can also read.
Now for the view; we will use the templating language ERB. We looked at examples of this in the Hotwire article, and it is pretty simple to pick up. We replace app/views/articles/index.html.erb with:
1 2 3 4 5 6 7 8 |
<h1>Articles</h1> <ul> <% @articles.each do |article| %> <li> <%= article.title %> </li> <% end %> </ul> |
This is the intermix of Ruby code and HTML that is both efficient, but also a bit messy for some people. Back on http://localhost:3000/articles, this shows us:
You can feel the flow here; route to controller to view. Because we know we will eventually exploit all of the CRUD elements through REST, we can jump ahead a bit here and prepare all the resources at once. Rails provides a specially named resources
route that maps all of the conventional routes at once.
If we asked Rails to list all the routes defined for our articles, we get the following:
If we now define the resources
route for articles within routes.rb:
1 2 3 4 |
Rails.application.routes.draw do get "/articles", to: "articles#index" resources :articles end |
We can then ask again about the routes. This time we see many more defined for us:
From here, you can just implement the corresponding controller methods one by one.
I think we have now gone far enough to understand the guts of the Rails system. You might be surprised at how much you can do as a developer with Ruby on Rails. Not everything has to be JavaScript-focused these days, so why not go back to the future with Rails?
See also: Return to the Rails Way: Installing Ruby on Rails in 2024