Ruby on Rails Generator Basics

www.kevinhaag.com

Ruby on Rails offers many tools to enhance your work flow, most of which are out-of-the-box features. This post will discuss just a few of the default generators that Rails can handle and how we might use them to our advantage.

[ START ]

To first see a list of your generators, open terminal and type ‘rails generate’. But an easier and quicker way, would be just:

$ rails g

Once that loads, you should see a list that looks like this:

Running via Spring preloader in process 65965
Usage: rails generate GENERATOR [args] [options]
General options:
-h, [ — help] # Print generator’s options and usage
-p, [ — pretend] # Run but do not make any changes
-f, [ — force] # Overwrite files that already exist
-s, [ — skip] # Skip files that already exist
-q, [ — quiet] # Suppress status output
Please choose a generator below.
Rails:
assets
channel
controller
generator
helper
integration_test
jbuilder
job
mailer
migration
model
resource
scaffold
scaffold_controller
task
Coffee:
coffee:assets
Js:
js:assets
TestUnit:
test_unit:generator
test_unit:plugin

[ ASSETS ]

From the above list, we’ll start with the assets command. This feature concatenates our assets, which can reduce the number of requests that a browser makes to render a web page. This allows for faster load times for your application.

Another feature would be asset minification; the process of removing all unnecessary characters from source code without changing its functionality.

“The third feature of the asset pipeline is it allows coding assets via a higher-level language, with precompilation down to the actual assets. Supported languages include Sass for CSS, CoffeeScript for JavaScript, and ERB for both by default.”

[ MAILER ]

Generate Mailer does what you might expect. It allows you to send emails from your application using mailer classes and views. Per the Ruby documents, Mailers have very similar design patterns as controllers. They inherit from a ::Base, live in the app folder, and they also include associated view files.

You can find more info about mailers by clicking here.

[ MIGRATION ]

I am currently using Ruby on Rails [5.0], but some of the resources I’ve looked up were explanations for older versions. Perhaps I had not noticed a typo, but it seems that previous versions were able to handle snake_case input, but [5.0] needed CamelCase.

Here is an example. I used the rails g migration to add a column to an existing table.

$ rails g migration add_color_to_vehicles color:string 

This should have produced a file in my db/migrate folder that looked something like this:

class AddColorToVehicles < ActiveRecord::Migration[5.0]
def change
add_column :vehicles, :color, :string
end
end

All I would need to do is rake db:migrate this file to add it into my schema. However, when opening up this file, add_column :vehicles, :color, :string was missing. Changing the command to CamelCase did fix this problem, and I was eventually able to get the correct results. And if you’re looking to remove this newly migrated column, it’s a fairly easy process. You’ll type into your terminal almost the exact same thing, with one exception. The word Remove.

$ rails g migration RemoveColorToVehicles color:string

This will now create a file that looks like this.

class RemoveColorToVehicles < ActiveRecord::Migration[5.0]
def change
remove_column :vehicles, :color, :string
end
end

If you’re wondering how rails knows to add or remove a column, or how it knows what table to edit, notice the beginning and ends of the command. Prepending with the words ‘Add’ or ‘Remove’ signals to rails we are going to make a column change to a table, and it finds the table by looking at what you appended this with. In our case ‘Vehicles’. Just one of the many luxuries rails has to offer!

[ MODEL ]

In a situation where you would need to generate only models, you can follow this process.

$ rails g model Vehicle name quantity:integer

This command will generate a Vehicle model, migration file, a Vehicle class and Vehicle table. We explicitly give it an integer to ensure correct labeling but since strings are the default, we do not need to specify a label with the name

class Product < ApplicationRecord
end
class CreateVehicles < ActiveRecord::Migration[5.0]
def change
create_table :vehicles do |t|
t.string :name
t.integer :quantity
t.timestamps
end
end
end

Here is a list of other field types including the recently used integer

integer
primary_key
decimal
float
boolean
binary
string
text
date
time
datetime
timestamp

A greater level of specification is also possible by appending parameters to the field type. If you were creating a price column where the maximum number should not exceed one million, you would type:

$ rails g model Product name price:decimal{8,2}

The 8 represents the total number of digits while the 2 provides the total number of digits to the right of the decimal. i.e. $123,456.78

*It’s important to note that when generating models, you do not create any views in order to display your information on the page.

[ CONTROLLER ]

As with all generators, they save you a large amount of time by writing boilerplate code, code that is necessary for the app to work.

Ruby offers a simple example of how one can use the custom generator.

$ rails g controller Greetings hello

This command creates a new controller in which you can customize.

class GreetingsController < ApplicationController
def
hello
@message
= "Never gonna give you up!"
end
end

Now in the view folder using ERB:

<h1>A Greeting for You!</h1>
<p><%= @message %></p>

While you can customize to your hearts content, and even create your own generators through rails generate. Limitless fun! There is also a massive community out there with a ton of gems that offer amazing time shaving custom generators. With quick research, you can find a custom generator gem that might solve a particular issue you’re working on. It’s important to keep in mind that installing a bunch of gems might not be the best idea. They can potentially make your application sluggish and a nightmare for future developers to work on/understand. It’s best practice to have a strong understand of what you’re dealing with in order to create an application that is both robust, fast and easy to navigate.

[ RESOURCE ]

For the most part, generate resource is very similar to generate model. The main difference being an additional controller, plus the appropriate routes.

class PetsController < ApplicationController
end
Rails.application.routes.draw do
resources :pets
end

[ SCAFFOLD ]

When you run this command, you’re essentially getting everything, even if you don’t need it. For that reason, it’s best for beginners to experiment with scaffold in order to get a better idea of the different relationships between all elements of your application. It is considered better practice to first generate a model, then controllers, views and routes as needed. This will give you more control in terms of looks and functions, all while avoiding unnecessary code. Scaffold does provide:

  • RESTful routes
  • A controller with all actions for RESTful handling of the model
  • Views needed by the controller
  • Tests stubs

If you were to run this command, it would look something like this.

class HighScoresController < ApplicationController
before_action :set_high_score, only: [:show, :edit, :update, :destroy]
# GET /high_scores
def index
@high_scores = HighScore.all
end
# GET /high_scores/1
def show
end
# GET /high_scores/new
def new
@high_score = HighScore.new
end
# GET /high_scores/1/edit
def edit
end
# POST /high_scores
def create
@high_score = HighScore.new(high_score_params)
respond_to do |format|
if @high_score.save
format.html { redirect_to @high_score, notice: ‘High score was successfully created.’ }
format.json { render :show, status: :created, location: @high_score }
else
format.html { render :new }
format.json { render json: @high_score.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /high_scores/1
def update
respond_to do |format|
if @high_score.update(high_score_params)
format.html { redirect_to @high_score, notice: ‘High score was successfully updated.’ }
format.json { render :show, status: :ok, location: @high_score }
else
format.html { render :edit }
format.json { render json: @high_score.errors, status: :unprocessable_entity }
end
end
end
# DELETE /high_scores/1
def destroy
@high_score.destroy
respond_to do |format|
format.html { redirect_to high_scores_url, notice: ‘High score was successfully destroyed.’ }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_high_score
@high_score = HighScore.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def high_score_params
params.require(:high_score).permit(:game, :score)
end
end

[ END ]