Deep Dive: Analyze the Rails Generators and How to Customize a Generator
In this deep dive guide we'll examine how generators work in Rails. Additionally, we'll walk through how to create a custom generator in Rails.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

In this deep dive guide we'll examine how generators work in Rails. Additionally, we'll walk through how to create a custom generator in Rails.

We covered a substantial amount of information in a short period of time. If you're still unsure about some of the elements we've just covered, I'd definitely recommend going through the guides again. The more times you view the information the more clear it will become.

In this deep dive section, I want to take an immersive look into what generators are, and how we can customize them.

Generators, whether the scaffold, controller, model or resource, are incredibly powerful, and one of the reasons why Rails became one of the most widely utilized frameworks in the world. Additionally, one of the impressive things about generators, is that they can be customized. That customization is what we're going to investigate in this guide.

Not only is it a benefit to learn how to customization a generator, the process of customization can clarify what generators do because you can see what occurs during every stage of the generation process. With that in mind, let's get started.

Deep Dives and how they Differ

Before we begin this demo, I want to make one clarification. These deep dives are separate from the rest of the course. My goal with these deep dive guides is to give you a laser like focus on a specific topic. We will not work on our main application during these specialized guides. The purpose of them is to take a step back, and really dig into the concepts.

I have seen many tutorials that only focus on one project. That is typically what I do, but you miss out on the ability to take a much deeper look at some of the more advanced components of the Rails framework.

Typically, in each deep dive, we will be creating brand new applications from scratch for the sole purpose of studying an isolated feature. So, in this guide we will be focussing on generators specifically.

Creating a New Application

Let's go to the terminal and create a new application in your Desktop folder. The command is
rails new GeneratorApp -T --database=postgresql

You can call your app whatever you want. In this instance Generator doesn’t have any special meaning. Remember the option -T means we will build without testing files and the option --database=postgresql designates that we want to use postgres instead of the default database. We are using these preferences just to follow the same pattern we used before.

Once the app is created, you can clear your terminal screen with the command clear.

Now, cd into your new app with the imperative cd <AppName>. If you followed along with my chosen name you would use:
cd GeneratorApp

Next, we'll create our database with the command rails db:create

The other reason I like to create different apps with these deep dives is, if you're new to Rails, and this is your first course, going through the process of creating multiple apps is actually very helpful, because it allows you to get familiar with the process. Soon, you'll be able to run these commands in your sleep!

Back to the Scaffold

Now that we have our application, let's talk about generators, specifically the scaffold.

We'll start by creating a scaffold with the command rails g scaffold Post title:string body:text

This command will generate a massive amount of content for us.

Next, we'll update the database with the code rails db:migrate

Now we want to run the rails server. If you don't have a screen splitting tool that will allow you to split your terminal screen into multiple windows, you can always press COMMAND +T, and this will open up another terminal window. Let's start the rails server rails s in the new terminal screen, so it won't get in the way of anything we do in the other.

Switch to the browser and go to localhost:3000, and you will see the Yay! Your on Rails site. Go ahead and add /posts to your url and you should see this screen:

large

Here, I can do all the CRUD functionality that was created with scaffolds, which is fantastic. However, there are a few things that can be bothersome with this generator.

First of all, notice how it gives us some really weird styles in our view. For example, as soon as you hover over a link, you get a black background.

This styling is generated when the scaffold runs and creates a stylesheet called scaffolds.scss. It is a file I've never used in a production application, so I don't see a point in having it. Thankfully, our generators are completely customizable, and we will discover how we can run a scaffold without creating this css file.

How to Customize

First we will discuss how to customize the generators by turning things on or off.

Next, we will explore a deeper level of customizing by modifying the content that is generated.

Let's open this code for our generator app in sublime. We have our views and our posts and all these great items we wanted. However, what if I don't want to have the scaffold stylesheet? Technically, I can go to app/stylesheets, right click on scaffolds.scss, and delete the file. This will remove those unwanted styles we saw in the browser. If you switch over now, you'll just see the default styles

Now you may think this styling is even more unappealing than the previous one --Yes, it is. What you are seeing now are the default HTML styles. The good news is, these defaults are easier to override and you will run into fewer conflicts using them. Usually, if I am starting an app completely from scratch, I prefer to start with these HTML defaults rather than the underdeveloped styles that scaffolds give you.

While it was easy to just delete that file, if you're building a big app, there's no point in deleting the css file, because every time you run a scaffold, it is going to generate those css files for you.

The Application.rb file

A better way to control the generator is to update to your main application file: config/application.rb.

require_relative 'boot'
require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_view/railtie"
require "action_cable/engine"
require "sprockets/railtie"
# require "rails/test_unit/railtie"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module GeneratorApp
  class Application < Rails::Application
    # Setting in the config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # —all .rb files in that directory are automatically loaded.
  end
end

To tailor the generator to our needs, we can paste a set of custom configuration items inside the GeneratorApp module, like this:

module GeneratorApp
  class Application < Rails::Application
    config.generators do |g|
      g.orm             :active_record
      g.template_engine :erb
      g.test_framework  :test_unit, fixture: false
      g.stylesheets     false
      g.javascripts     false
    end
  end
end

This configuration will manage all the different generators we have. The code

config.generators do |g| 

indicates that for ever every generator that runs the items in the method should be set as follows:

  g.orm    :active_record 

The orm should be set to active_record. This means the app should use the standard Rails default connection to the database. It would be a rare occasion that you would change this setting, for example if you wanted to connect to a new SQL database, or something custom.

 g.template_engine :erb

Next, is our template_engine. You can see this is set to erb, which is what we will be using in this course. However if you want to use Slim or HAML, you could change the erb to slim or haml respectively, and this code would use the corresponding templating engine. We're not going to change it for this course, but it's definitely something you should know is available to you.

g.test_framework  :test_unit, fixture: false

Moving on, you'll need a test_framework. Though we skipped the test environment, and we do not have a test directory, in a production environment, you will want to have tests. Scaffolds is going to create some tests for you, and you can define which test framework you want to use. By default it is :test_unit. You can choose to have a different testing framework such as rspec, or whichever framework performs best for your application.

g.stylesheets     false
g.javascripts     false

Next, is our stylesheets parameter. With this parameter, you can tell the generator whether you want to generate stylesheets or not. It is the same case with javascript. Here we’ve obviously chosen not to create them by using false.

Viewing the Results

Now that we have set these custom settings for our generators, let’s go ahead and save the file and return to the terminal.

We can run another scaffold generator: rails g scaffold Blog title:string

Let's also migrate the database with the command rails db:migrate

Remember my rails server is running in the background, so I don't have to start it up again. I can just switch to the browser and go to localhost:3000/blogs. If you hover over the New Blog link, you can see there is no black background, so those scaffold.css styles were not added.

You can also go to your file tree in sublime and look to app/stylesheets. You'll see that it did not generate any custom stylesheet for blogs. Likewise, it did not create a custom javascript file for blogs.

There may be times when you don't want stylesheets created, but you do want a javascript file. Simply change the configuration to true for javascripts.

module GeneratorApp
  class Application < Rails::Application
    config.generators do |g|
      g.orm             :active_record
      g.template_engine :erb
      g.test_framework  :test_unit, fixture: false
      g.stylesheets     false
      g.javascripts     true
    end
  end
end

If you run the scaffold generator again, rails g scaffold Guide title:string, then rails db:migrate

You can see in your terminal that it did create a javascript file for us in app/assets/javascripts/guides.coffee

This shows the level of granularity you can get by turning things on and off with your configuration parameters.

Even More Customization

Now, to some more in-depth customization! Let's say you really loathe the way the scaffold sets up your data in tables.

medium

Notice this table format that Rails uses for displaying records? Though tables are great for presenting tabular data, you may sometimes want the data to be displayed side-by-side or in paragraph form. There is a way to fix this!

One way is to go to your blog's index.html.erb page and make all styling changes there. The problem is you'll have to make the same change every time you run a scaffold. For example, let's say you changed the style to match your website design in your blog's index.html.erb file. Next, you create another feature, say posts. You'll have to go and make those same exact changes in post's index.html.erb file too. That would be incredibly redundant!

Instead, you can customize what is generated, and it is relatively straightforward to do. To begin, go to your lib directory. We'll cover this directory in depth later in the course, but for now, understand that lib allows you to have an external source of customization for your app. Essentially, we're going to make custom styles that will override the default styles for you. For that, we need to create a new directory called templates.

(Developers note: to create the new directory in the lib, right click on the lib directory and select New Folder, and give it the name templates)

Inside of templates we will create two more directories. First, we're going to create a directory called erb. It is titled 'erb' because we are using the ‘erb’ syntax. If you are using Haml, or some other templating engine, you would use that as the directory name.

Next, we will create another directory called scaffold inside of erb. This may seem like a lot of directories, which technically it is, but this is the way it needs to be organized for our override to work.

Inside this scaffold directory, I'm going to create a file called index.html.erb.

(Developers note: to create a new file right click on the folder and choose new file, then give it a name and hit enter)

The process of creating this file set up will allow us to override our index action. Though we can do this for any action, such as the show, new, form, or any of those, for demonstration purposes, I think the index is the easiest to demonstrate and understand.

So here in our lib/templates/erb/scaffold/index.html.erb file, we can technically override whatever we want. We could add:

 <h1>My  post</h1>

Then, when we run a scaffold it would simply create this tiny file that displays this one title. This would not be very effective, and it would basically defeat the purpose of having scaffolds because the biggest advantage of scaffolds is that it builds all that functionality for you! Rather, what we will do, is override and customize the default behavior. The easiest way to do that is by copying and pasting the source code from Rails.

Go to https://gist.github.com/jordanhudgens/2023f69b3a16d13c86d57091eec39fe9

Since we're going to override index.html.erb, copy that code and paste in your new file.

<p id="notice"><%%= notice %></p>

<h1><%= plural_table_name.titleize %></h1>

<table>
  <thead>
    <tr>
<% attributes.reject(&:password_digest?).each do |attribute| -%>
      <th><%= attribute.human_name %></th>
<% end -%>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <%% @<%= plural_table_name %>.each do |<%= singular_table_name %>| %>
      <tr>
<% attributes.reject(&:password_digest?).each do |attribute| -%>
        <td><%%= <%= singular_table_name %>.<%= attribute.name %> %></td>
<% end -%>
        <td><%%= link_to 'Show', <%= singular_table_name %> %></td>
        <td><%%= link_to 'Edit', edit_<%= singular_table_name %>_path(<%= singular_table_name %>) %></td>
        <td><%%= link_to 'Destroy', <%= singular_table_name %>, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <%% end %>
  </tbody>
</table>

<br>

<%%= link_to 'New <%= singular_table_name.titleize %>', new_<%= singular_table_name %>_path %>

One of the most advatageous things about open source software is that all this code is freely available to us. These files give us the ability to learn from some of the best Rails developers the world. When you study their code, you can learn a great deal by reverse engineering the processes they have created. I've taught myself quite a bit about Ruby and Rails framework just by looking at the source code.

Going back to our new file, if you run this as it is, it will give us no overrides. It will simply give us exactly what the system already has. There would not really be a point to doing that. So we can customize it to have the changes we want.

For example, I want to change the title size from an <h1> to an<h2> sized heading.

<h2><%= plural_table_name.titleize %></h2>

Let’s also make some other changes. We can go to the browser and create another blog to see how the view behaves. There are a few things I think we should change. We’ve already reduced the size of our heading, we can also add a horizontal line and remove the table. While designing content, it's pretty rare I use tables as I prefer to have the items stacked over one another, so let’s look at the best way to do that.

Back in sublime in our file for override changes, let’s add a horizontal line <hr> under our header.

<p id="notice"><%%= notice %></p>

<h1><%= plural_table_name.titleize %></h1>

<hr>

<table>

You will notice at the top of the file there is a line that references ‘notice’. Remember when you go through the process of creating a new blog in the browser a notice pops up at the top of the screen that says, Blog was successfully created . You do not see this notice a lot on the index action, so you don’t really need to be concerned with it here, but it is good to know that if you were creating another app, where you would use notices, you do have the option of moving it wherever you like on the page. You can rearrange all the items in this view however you want. We will do some of this customization in our Portfolio app. For now you could just move the notice under the heading. You won’t actually see that right now because you will be redirected to the show page.

<h1><%= plural_table_name.titleize %></h1> 

<p id="notice"><%%= notice %></p>

<hr>

<table>

So we’ve add the horizontal line with the code <hr> . It will be displayed under the heading to split the page and give some definition.
Next, I want to get rid of the table completely. Select and remove this code from your file:

<table>
  <thead>
    <tr>
<% attributes.reject(&:password_digest?).each do |attribute| -%>
      <th><%= attribute.human_name %></th>
<% end -%>
      <th colspan="3"></th>
    </tr>
  </thead>

You will also need to remove the closing </table> tag

Next, you will need to select the table body section found between the <tbody> </tbody> tags, and move the whole set of text to the left. Essentially you are removing the current indentation.

Next, we'll change the <tbody> and </tbody> to <div> and </div> respectively.

The<tr>and<td> tags are related to tables, so we need to update those as well. The <tr> tags we will change to <div> tags, and the <td> tags we will change to <p> paragraph tags.

Sublime Tip

You could hold the command key and double click on each <td> tag to select and change them, but there is an easier way. Hit COMMAND+F. This will open the search box at the bottom of the screen. In the search box type td, then click on the "Find all" button. This will select all the instances of td for you. Simply type in p and it will update all the td tags to paragraph tags.

Another change I like to make is to replace the word "destroy". That language seems a bit odd so I want to change it to "delete".

<td><%%= link_to 'Delete', <%= singular_table_name %>, method: :delete, data: { confirm: 'Are you sure?' } %></td>

Lastly, instead of a link that just reads “new” followed by the item title, I'm going change the link to read "Create a New” item.

<%%= link_to 'Create a New <%= singular_table_name.titleize %>', new_<%= singular_table_name %>_path %>

The customized file should now look like this:

<h2><%= plural_table_name.titleize %></h2>

<p id="notice"><%%= notice %></p>

<hr>

<div>
  <%% @<%= plural_table_name %>.each do |<%= singular_table_name %>| %>
    <div>
<% attributes.reject(&:password_digest?).each do |attribute| -%>
      <p><%%= <%= singular_table_name %>.<%= attribute.name %> %></p>
<% end -%>
      <p><%%= link_to 'Show', <%= singular_table_name %> %></p>
      <p><%%= link_to 'Edit', edit_<%= singular_table_name %>_path(<%= singular_table_name %>) %></p>
      <p><%%= link_to 'Destroy', <%= singular_table_name %>, method: :delete, data: { confirm: 'Are you sure?' } %></p>
    </div>
  <%% end %>
</div>


<br>

<%%= link_to 'Create a New <%= singular_table_name.titleize %>', new_<%= singular_table_name %>_path %>

This is just an example to show you the different kinds of things you can do to override the rails defaults.

Real World Instance

To give you a real-life example, if I am working on a project for a client, I would usually be given a layout created by a designer. I would implement the code for it here in this override file. Most likely I'll work with some pre-existing css styles. So, right away I would add those classes to the corresponding divs here in in the generator.

For example, I would add a css class to a div: <div class=“content”> or whatever style I am using for the application. So when I run a generator the files would already have those styles built in.

This is Not Retroactive

One thing to note is that these overrides are not retroactive. If you go back to the browser and hit refresh, you will see that nothing changes even though we have made changes to this file. This template is created so that all the future generators and scaffolds I run will use these styles. Usually, I do create the template early on in the life cycle of a new project so this code will be applied to all the generators and scaffolds.

Switching back to the terminal, let’s create a new scaffold: rails g category title:string description:text

You will get an error message, Could not find generator ‘Category’ The command didn't execute because I didn't indicate what type of generator I wanted to use.

So, the correct code is: rails g scaffold Category title:string description:text

That will create everything for us. Now we have to migrate the database with the command: rails db:migrate . Your rails server should still be running, so when you switch over to your browser, and go to localhost:3000/categories, you should see the updated design.

large

Notice you have the horizontal line, a different heading and a more understandable link.

If you click on Create a New Category, Add a title and description and hit enter you will be able to see how it is now displayed. The data is no longer in a table form, but is stacked on top of one another.

large

So, we have overridden all the default layout for the scaffold generator. All that we had to do was customize and adjust the lib/templates/erb/scaffold/index.html.erb file to reflect what we wanted. So, every time the scaffold runs in the future, it will create a customized index file for us instead of the default one provided by Rails.

Rails Guide to Customization

Before we end, I want to introduce one more item. There are many more customizations you can do with generators. I recommend you go through the Creating and Customizing Rails Generators & Templates guide provided by Rails. You will discover all the different things you can do.
For example, you can create a generator completely from scratch. In other words, if you have a set of settings that you want for your application you can dynamically add them. You can also create your own layouts. Rails gives you so much control building your apps. This guide is a highly valuable tool to explore and run through different options to see what you can build with your own customizations.

Even if you won’t be using a lot of the tools found in this Rails guide, it is beneficial to know what choices exist. Simply by going thru this content, you will learn a lot about how rails works and what generators do, which in turn, is going to help your overall Rails knowledge.

See you in the next section.

Resources