Creating a custom Ruby on Rails Stimulus generator

If you’ve spent any time working with Ruby on Rails, you know that using generators can save you from a lot of console commands and copy/pasting from one file to the next. Need a new model? Just run rails g model MyNewModel name:string description:string and you’re set.

Rails covers most of the common use cases for you with built-in generators. If the built-in generators don’t meet your needs, you can get fancy by creating your own custom generators. Custom generators can save you time any time you’re finding yourself running lots of touch commands and copy/pasting boilerplate into new files.

Although Rails provides built-in generators for most things that Rails projects need, one common use case that’s missing is a generator for new Stimulus controllers. Stimulus, a modest JavaScript framework created by the team at Basecamp, is an increasingly common part of the Rails stack.

Despite its growing popularity, Rails does not provide a generator out of the box (as of Rails 6.0). Without a generator, every new Stimulus controller requires a manual touch app/javascript/controllers/my_new_controller.js in the console and then copying from another controller, changing the class name, and otherwise doing stuff uninteresting stuff before you start building something new. No fun.

Today we’re going to solve this problem by learning how to build our own custom generator for Rails. Our custom generator will create new a new Stimulus controller in the app/javascript/controllers directory when we run rails g stimulus ControllerName.

Let’s get started.

Setup

Generating a generator

We’ll use the generator generator to generate a new Stimulus generator. Still with me? Great. Run this in your console and let’s move on from generating generators:

rails g generator stimulus

This applies Rails magic to create the bones of our generator, named stimulus, in the lib directory. You’ll notice that inside of the lib/generators/stimulus directory there are a few files and an empty templates directory. We’ll briefly talk about what each of these items is and then we’ll create our generator.

A screenshot showing the files created after running rails g generator stimulus in a terminal.
A screenshot showing the files created after running rails g generator stimulus in a terminal.

stimulus_generator.rb: This is the file that runs when you type rails g stimulus in your console. The class defined here will manage creating a new file each time the generator runs, and populating that file with the content from our template Stimulus controller.

USAGE: This file contains instructions for users of your generator. The contents of this file are printed when you type rails g stimulus in your console.

Templates: The templates directory contains any files that your generator will copy when it runs. In our case, we’ll just have one file. These template files can access and insert variables into the template, when needed.

stimulus_generator_test.rb: The generator generator helpfully creates a test file, which can be run (in our case) with rake test. Our generator is simple, but we’ll add a test to make sure it works as we expect.

Adding our code

Let’s first add a test to our stimulus_generator_test file. We’ll use this test to make sure our generator works without having to generator a Stimulus controller we don’t want.

In lib/generators/stimulus/stimulus_generator_test.rb add a test that runs our generator and validates that a new file is generated as expected:

When we run rake test the test will fail, which is expected since our generator hasn’t been built yet. Let’s work on making it pass.

First, create the template file that our generator will copy each time it runs. This file will live in the templates directory:

touch lib/generators/stimulus/templates/controller.js

In this new file, we’ll insert the content of our Stimulus controller:

My template includes the basic structure of a Stimulus controller plus the lifecycle methods I find myself using most often, that’s what makes the most sense to me. You can include more lifecycle methods or just leave out everything but the class definition, you’re the boss of your own template file.

With our template file created, we can go into our generator file and tie the generator and template together:

Each time rails g stimulus Something is called, any method in this file will run. In our case, we just create a new file from our template using the template method (provided by Thor, if you’re interested in the inner workings of Rails generators). If we want to handle conflicting file names, make our file name generation smarter, process additional arguments or otherwise make our generator more powerful we can add additional methods to do so. For our purposes, we will keep things simple.

With our template and our generator class built, let’s see if our tests pass:

Screenshot showing the result of running rake test in a terminal, with 1 test run, 1 assertion, and 0 failures.
Screenshot showing the result of running rake test in a terminal, with 1 test run, 1 assertion, and 0 failures.

Perfect! We’ve got a working generator and we can run that generator with rails g stimulus CoolIdea

If you’ve followed along with me through this tutorial, when we run the generator our new controller will be created at app/javascript/controllers/cool_idea_controller.js and it will be populated with the content from our controller template file.

Congratulations on making it this far! You’re a star.

Our last step is to update the USAGE file for our generator with useful information for others who encounter our generator in the future. Something like this will work fine:

Description:Stubs out a new Stimulus controller.This generator accepts one argument, the name of the controller, CamelCased or under_scored.Example:`rails generate stimulus Thing`This will create a new Stimulus controller at `app/javascript/controllers/thing_controller.js`

Now when we run rails g stimulus our help text will be printed to the terminal. The generator is pretty simple today, but in the future we might add additional arguments or options. Starting with documentation from day one is always the better plan.

Wrapping up

While our example was simple, the same technique can be applied to create sophisticated new generators for Service Objects, complex Stimulus controllers, or any other resource you find yourself needing. In addition to creating our own custom generators, we can also use this knowledge to change the default generators provided by Rails. Overriding the default model or controller generators can help your organization enforce code standards across an organization or just save you from copying boilerplate across your project.

For more reading on the power of Rails generators, start with the Rails guide on generators.

Finally, if creating your own Stimulus generator isn’t a chore you’re looking forward to, I’ve published a gem you can use to add Stimulus generator just like the one in this tutorial to your Rails projects.

Questions or feedback? Find me on Twitter, or leave a note here.

Written by

Product, engineering, and marketing leader @CareerPlug. I care about being kind, helping others grow, and building cool things. Infrequent tweets @davidcolbyatx

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