I usually write in Japanese, so please pardon any awkward phrasing in my English.
Introduction
None of us want to log into a production environment via SSH and manually fiddle with data using rails c
, right? Surely no one is doing that… or at least, let’s hope not.
That said, in some workplaces that aren’t fully set up yet, it might still happen occasionally. I’ve found myself doing it now and then, and I started wondering if there was a better way.
With that in mind, I experimented with a potential solution by creating a new Gem. (Full disclosure: I’m quite new to making Gems.)
This Gem also ties into the script
folder, a feature introduced in Rails 8.
In this article, I’ll cover:
- The challenges of data migration
- An introduction to the relatively unknown
script
folder in Rails 8 - The new Gem I’ve created to tackle these issues
But first, let’s jump right into what I made.
The Gem I Created: Scriptor
What can it do?
- Browse your
script
folder’s code right in the browser - Execute scripts from the
script
folder via the browser - View execution history of those scripts through the browser
Check out the repository here:
https://github.com/hatsu38/scriptor
Before I dive into the background of why I made it, let’s talk about how data migration is often handled.
How Do You Handle Data Migration?
Data migration strategies often come up in discussions. Common approaches include using maintenance_tasks gem, data_migrate gem, or simply running rake tasks
.
I personally rely on the maintenance_tasks gem at work. The Rails Guide even recommends using maintenance_tasks instead of manipulating data directly in migrations.
However, if your needs aren’t extensive enough to justify maintenance_tasks, it’s still common to write and run a rake task
. Before maintenance_tasks came along, that was often the go-to solution.
Among the variety of options available, a new but relatively unknown feature was introduced with Ruby on Rails 8.0.0: the script
folder.
This feature was added via this pull request:
https://github.com/rails/rails/pull/52335
About the script
Folder
The Rails Guide describes the script
folder as:
A place to store disposable or general-purpose scripts and benchmarks.
The script/USAGE file further clarifies:
Generate a one-off or general purpose script, such as a data migration script, cleanup script, etc.
In other words, the script
folder is well-suited for one-off data migrations. Quietly and without much fanfare, Rails 8 introduced a first-party solution for these single-run data migration needs.
How to Use the script
Folder
Using the script
folder is straightforward. Just run:
bin/rails generate script my_script
This command generates a file at script/my_script.rb
with the following default content:
require_relative "../config/environment"
# Your code goes here
You can modify this file to include any Rails code you need.
For example, you might write a quick data migration like this:
require_relative "../../config/environment"
title, body = ARGV
if post = Post.find_by(title: title)
post.update!(body: body)
puts "Post updated!"
else
Post.create!(title: title, body: body)
puts "Post created!"
end
To run it, simply do:
ruby script/my_script.rb hello world
This approach is handy for simple, one-off scripts. For more background, you might check out this discussion:
Is there any “official” way to organize one-off scripts?
Running These Scripts from the Browser and Managing Execution History
While the script folder is convenient, there’s still a catch: I don’t want to SSH into production to run these scripts. Ideally, I’d like to run them from a browser and keep an execution log for auditing purposes.
That’s exactly why I created Scriptor.
Once again, here’s a quick look:
https://github.com/hatsu38/scriptor
A Quick Overview of Scriptor
Scriptor allows you to:
- Browse scripts from the script folder via the browser
- Execute these scripts from the browser
- View a history of past executions
For example, let’s say your script folder looks like this:
❯ tree script
script
├── migration
│ ├── hoges.rb
│ └── posts.rb
└── my_script.rb
2 directories, 3 files
Navigating to http://localhost:3000/scriptor displays a list of these scripts:
Clicking on a script’s detail page shows its code:
From this page, you can click the 🛠️Run Script
button to execute the script. If the script requires arguments, you can input them into a text field before execution.
At the bottom of the page, you can view the execution history:
The execution history stores:
- Status (running, success, error)
- Start time
- End time
- Executed command
- Targeted file
And more.
Installation
It’s easy to get started:
-
Add the gem:
bundle add scriptor
-
Run the installer:
bin/rails generate scriptor:install
This will:
- Add
mount Scriptor::Engine => "/scriptor"
toconfig/routes.rb
- Create a migration file
****_create_scriptor_executions.scriptor.rb
- Add
Place your scripts in the script folder, and they’ll appear at http://localhost:3000/scriptor.
That’s it! You’ve got a handy way to run and manage scripts directly from the browser.
Conclusion
Rails 8 introduced the script folder as a first-party solution for running one-off scripts, including simple data migrations. Wanting to leverage this feature more conveniently, I ended up building a Rails Engine Gem—Scriptor—to execute these scripts from the browser and log their histories.
I’m new to Gem development, but I had a lot of fun making it, and I think it turned out pretty well. Of course, it’s still missing some features like English documentation and comprehensive tests, so contributions are welcome. Stars on GitHub are also much appreciated!
Check out the repo:
https://github.com/hatsu38/scriptor
Thanks for reading!
Top comments (3)
Thanks for the guide! Since creating rails 8 apps, I've noticed the /script folder but didn't pay attention.
Great work on scriptor btw - I like the idea of being able to run scripts from a GUI in prod. Will try
*will try the gem
Thanks for this, I just started checking out Rails 8 and I'm looking into this script runner feature. I have always used rake tasks for this purpose but your gem looks very nice for data management.