Rebuilding LoreScroll: A Guide to Rails Generators

One of my favorite early coding projects was a Ruby On Rails application called LoreScroll that was designed to help storytellers organize their worlds, characters and stories in a single, easy-to-navigate tool. It was an ambitious idea that worked out, but not at the scale I was hoping. As a tool to help me reinforce and continue my learning, I’ve decided to go back to LoreScroll and reconstruct it from the ground up using some of the new technology I’ve learned since — and to bring you along for the ride.

Since I’m starting completely from scratch, I need to build out my backend to serve as an API to store story data from my users. I already have a baseline of what I’m looking for, so I’ve decided to use Rails Generators to speed up the process.

As such, this feels like a great time to talk about Rails Generators, what they do and when is the best time to use them.

What Are Generators?

One of the benefits of Ruby On Rails is that focuses on convention, a common set of agreed upon rules that make it fairly simple to read and interpret to those who know the convention. This is especially true of the way in which Rails apps are structured. Files and folders are organized in a specific pattern and even the code itself is often laid out in such a way that it encourages efficiency and ease-of-use, allowing the engineer to focus solely on solving problems.

Rails generators (activated using the ‘rails generate’ or ‘rails g’ command) help us to exploit our knowledge of convention to quickly stub out the basics of our Rails application — controllers, models, migrations, etc — so that we can get started on the more complex code development faster. This saves us a lot of time!

Model

rails generate model ModelName column_name:datatype

The Model generator creates two files for us: a model file and a migration file. This allows us to quickly set up our database tables and connect them to models.

  1. Type ‘rails generate model’ into your terminal.
  2. Follow that with the name of Model, which should be a single word. If you need to use more than one word to describe your model, be sure to use CamelCase.
  3. Follow that with a list of information about your database columns, including the name of the column and type of data it will include. You can include as many of these as you require to fill out your database table.
  4. When you hit enter, the files will generate. Let’s look at an example:
rails generate model World name:string scale:string description:string### This creates two files. db/migrate/20210619003449_create_worlds.rbclass CreateWorlds < ActiveRecord::Migration[6.1]
def change
create_table :worlds do |t|
t.string :name
t.string :scale
t.string :description
t.timestamps
end
end
end
app/models/world.rbclass World < ApplicationRecord
end

We’ve generated a CreateWorlds class that contains a table with three columns, a string called name, a string called scale, and a string called description. We’ve also generated an empty model called World which we can edit as needed.

Note how this generator automatically implements Rails convention. The only information we provided it was that we wanted to name our model World, which it did. But it also takes that information and knows how to format it for our other files. Our migration class is called CreateWorlds. Our table is called :worlds. All we need to supply is that little bit of information and the generator does the rest of the work for us. We’ll see this on a larger scale with our other options.

The Model generator is the lightest weight of our generators, creating a low number of files. But that’s also what makes it so useful. Remember, the more files you generate, the messier your project is going to get. You don’t want to fill it up with unused, empty files. The Model generator allows us to only generate files that we know we’re going to use.

Migration

rails generate migration MigrationName column_name:datatype

Sometimes we only need a migration without the associated model, especially if we’re modifying an already existing table. In this case, we use the Migration generator, which will only generate a migration file. The instructions are practically identical to those provided previously, only the results are different. However, the formatting of the name may depend on the type of migration you’re trying to accomplish.

### CREATE A TABLErails generate migration CreateStories title:string summary:stringdb/migrate/20210619003351_create_stories.rbclass CreateStories < ActiveRecord::Migration[6.1]
def change
create_table :stories do |t|
t.string :title
t.string :summary
t.timestamps
end
end
end
### ADD A NEW COLUMNrails generate migration AddGenreToStories genre:stringdb/migrate/20210619003352_add_genre_to_stories.rbclass AddGenreToStories < ActiveRecord::Migration[6.1]
def change
add_column :stories, :genre, :string
end
end
### REMOVE A COLUMN rails generate migration RemoveGenreFromStories genre:stringdb/migrate/20210619003353_add_genre_to_stories.rbclass RemoveGenreFromStories < ActiveRecord::Migration[6.1]
def change
remove_column :stories, :genre, :string
end
end
### DROP (OR DELETE) A TABLErails generate migration DropStoriesclass DropStories < ActiveRecord::Migration[6.1]
def change
drop :stories
end
end

You can see that the only thing we need to do to change the migration type is to indicate it in the name. If we want to create a new stories table, the name becomes CreateStories. If we want to add a genre column to an existing stories table, the name becomes AddGenreToStories. If we want to delete a genre column from an existing stories table, the name becomes RemoveGenreFromStories. And if we want to delete the stories table altogether, the name becomes DropStories. The generator handles the rest for us.

Note: Remember, the Migration generator will only create the migration files. You will still need to actually run ‘rake db:migrate’ in your terminal to build the database schema.

Controller

rails generate controller PluralName actions

The Controller generator does a lot more work for us. It creates a number of files for us: including a controller, views for that controller, tests, routes and many others. It’s a tool that’s great for quickly building static pages that won’t require any use of CRUD actions (Create, Read, Update, Delete).

  1. As always, we start by typing ‘rails generate controller’ into our terminal.
  2. Next, we include a name. This name should be pluralized (i.e. Users instead of User or Games instead of Game) to ensure convention is kept.
  3. Finally, we add a list of the actions we would like to take in our controller.
  4. Optional: If you’re not interested in creating test, include the tag — no-test-framework at the end of the line.
  5. When we submit this generator the following files will be created:
rails generate controller Stories index show --no-test-frameworkcreate  app/controllers/stories_controller.rb
route get 'stories/index' get 'stories/show'
invoke erb
create app/views/stories
create app/views/stories/index.html.erb
create app/views/stories/show.html.erb
invoke helper
create app/helpers/stories_helper.rb
invoke assets
invoke css
create app/assets/stylesheets/stories.css
app/controllers/stories_controller.rbclass StoriesController < ApplicationController
def index
end

def show
end
end

This is a lot of generated code (and future generators will give us even more than this) — so let’s break down what we’ve got here.

  • Our StoriesController file that inherits from ApplicationController and includes empty index and show actions.
  • Routes to match our index and show methods.
  • A views directory that includes a stories folder, containing views files for each of our actions: index and show.
  • A folder containing all of our stories helper scripts.
  • A CSS stylesheet to allow us to style our views.

All of these files would be useful in certain contexts, but there is a real risk that you’ll have some wasteful code if you use this generator. As such, use it sparingly and only when you feel that everything it generates will be of use to you. It is also recommended that you avoid using this generator to create CRUD actions in your controller because each of those actions will receive corresponding views that will likely go unused. Stick with static actions like index and show unless you absolutely need to.

Resource

rails generate resource Name column_name:datatype

Now we’re getting to the big boys. The Resource generator gives us basically everything we need to create a single, full-functioning MVC resource in Rails: a model, a controller, and views. This is absolutely perfect for building out an API like I’m attempting to do with LoreScroll.

rails generate resource World name:string scale:string summary:string --no-test-frameworkinvoke  active_record
create db/migrate/20220421042201_create_worlds.rb
create app/models/world.rb
invoke controller
create app/controllers/worlds_controller.rb
invoke erb
create app/views/worlds
invoke helper
create app/helpers/worlds_helper.rb
invoke assets
invoke css
create app/assets/stylesheets/worlds.css
invoke resource_route
route resources :worlds
db/migrate/20220421042201_create_worlds.rbclass CreateWorlds < ActiveRecord::Migration[5.2]
def change
create_table :worlds do |t|
t.string :name
t.string :scale
t.string :summary
t.timestamps
end
end
end
app/models/world.rbclass World < ApplicationRecord
end
app/controllers/worlds_controller.rbclass WorldsController < ApplicationController
end
config/routes.rbRails.application.routes.draw do
resources :worlds
end

Let’s do another quick breakdown of what was created:

  • A CreateWorlds migration that builds a table with three columns: a string named name, a string named scale, and a string named summary.
  • A World model file that contains an empty class.
  • A WorldsController file that contains an empty controller.
  • A folder to contain our views for worlds.
  • A folder to contain our worlds helper scripts.
  • A CSS stylesheet for styling.
  • A route for :worlds.

This is basically everything we need to get our World resource up and running. The interesting thing is that while the Resource generator creates several more files than the Controller generator, they are mostly blank and don’t include any of our controller actions. As such, there is less likely to be wasted code. You should still be careful not to overuse this tool, but it is one of the better options amongst the more complex generators.

Scaffold

rails generate scaffold Name column_name:datatype

Which brings us to the last major generator we’re going to talk about: Scaffold. This is a very tempting tool that basically creates an entire functioning Rails application from scratch. It is amazing to watch unfold. However, before I even demonstrate the power of the Scaffold generator, I would urge you to hesitate before you use it. It creates so many extraneous files that you will likely be building an application that is much larger than necessary and that contains a myriad of unused code. It can also be difficult to debug since you, yourself, did not create the structure of the application. It is an option, but be wary of it. I find it best used when I’m trying to test out ideas — not for final projects.

rails generate scaffold World name:string scale:string summary:string --no-test-frameworkinvoke  active_record
create db/migrate/20220421042201_create_worlds.rb
create app/models/world.rb
invoke resource_route
route resources :worlds
invoke scaffold_controller
create app/controllers/worlds_controller.rb
invoke erb
create app/views/worlds
create app/views/worlds/index.html.erb
create app/views/worlds/edit.html.erb
create app/views/worlds/show.html.erb
create app/views/worlds/new.html.erb
create app/views/worlds/_form.html.erb
invoke helper
create app/helpers/worlds_helper.rb
invoke jbuilder
create app/views/worlds/index.json.jbuilder
create app/views/worlds/show.json.jbuilder
invoke assets
invoke css
create app/assets/stylesheets/worlds.scss
invoke css
create app/assets/stylesheets/scaffolds.scss

This looks a lot like what our Resource generator built out for us with a few added files. You’ll see that this time around we’ve also got views for each of our controller actions, as well some JSON files.

However, the truly impressive bit comes when we look inside the files, especially our controller. Our controller contains every RESTful route we need for a fully functioning CRUD application.

class WorldsController < ApplicationController
before_action :set_world, only: [:show, :update, :destroy]
def index
@worlds = World.all
render json: @worlds
end

def show
render json: @world
end
def create
@world = World.new(world_params)
if @world.save
render json: @world, status: :created, location: @world
else
render json: @world.errors, status: :unprocessable_entity
end
end
def update
if @world.update(world_params)
render json: @world
else
render json: @world.errors, status: :unprocessable_entity
end
end
def destroy
@world.destroy
end
private

def set_world
@world = World.find(params[:id])
end
def user_params
params.require(:world).permit(:name, :scale, :summary)
end
end

What’s more, we also get completed views associated with each of these actions. When we spin up a server, we can actually use a simplified version of our application, complete with a form that allows us to add new worlds, edit them and delete them from the database, as well as view a complete list or each world individually. It is sometimes described as magic, but it’s just a very powerful generator.

Final Thoughts

Rails generators are easy-to-use tools that help us to save time and prevent long stretches of repetitive coding. When used intelligently, they can help us to do all of the grunt work, so that we can get to the fun, creative part of coding our backend — and eventually our frontend. I hope this has been a helpful guide and that you’ll get some use out of these generators your self.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store