The Rails generator is a great tool to speed up your workflow, but having to manually open just-generated files gets tiresome fast. We’ll see how to automatically open up all generated files in your editor, accelerating your workflow even more.
TL;DR
Don’t care about how it works, just want to use it?
- Download the small script file
- Change the
subl
editor command to fit whatever editor you’re using - Make the file executable (
chmod +x rails_g_and_open.rb
) - Create a shell alias that you’ll use as a substitute for
rails generate
, for example:
alias rg="~/scripts/rails_g_and_open.rb"
# Now you can run:
# $> rg model user
If you’re using Tmux, follow these additional steps to make it work.
Read on for details on how it works!
First Implementation
The idea is simple enough: run the rails generate command, capture the output, and load all generated files. As a reminder, the output of a rails generate
command looks like this:
$> rails generate model device invoke active_record create db/migrate/20150720054739_create_devices.rb create app/models/device.rb invoke test_unit create test/models/device_test.rb create test/fixtures/devices.yml
We want to extract all paths that start with create and pass those to our editor. We also need to ignore created directories, since they might cause the editor to open a new window. A simple solution is easy:
#!/usr/bin/ruby def extract_created_files(lines) created_items = lines.map do |line| command, file = line.split file if command == "create" end.compact created_files = created_items.reject { |file| File.directory?(file) } created_files.reverse end output = `rails generate #{$*.join(" ")}` lines = output.split files = extract_created_files(lines) puts output if files.any? puts "\nOpening files #{files.join(", ")}..." exec("subl #{files.join(" ")}") end
This does exactly what we want it to, except that for some reason the colouring has been removed from the output, and I really like the colours.
Adding Colours Back
Turns out that Rails uses the gem thor as the framework for its command-line interface, and thor only enables color when it runs in a terminal. Since we’re running the generate
command in our own script, there is no terminal and thor disables the shell formatting.
To fix this we have to capture the output using a virtual terminal or pseudo terminal which is just a fake terminal that we can control with code.
Here’s the updated, final script with colours added back in. Note that we have to filter out the colours again before parsing the output.
#!/usr/bin/ruby require 'pty' def extract_created_files(lines) created_items = lines.map do |line| command, file = colorless(line).split file if command == "create" end.compact created_files = created_items.reject { |file| File.directory?(file) } created_files.reverse end def colorless(str) str.gsub /\033\[\d+m/, "" end command = "rails generate #{$*.join(" ")}" lines = [] # Use PTY to force Thor to output coloured text PTY.spawn(command) do |r, w, pid| begin while line = r.readline puts line lines << line end rescue EOFError # noop end end files = extract_created_files(lines) if files.any? puts "\nOpening files #{files.join(", ")}..." exec("subl #{files.join(" ")}") end
Addendum: Tmux Fix
If you’re using Tmux on Mac, you have some additional hoops to jump through to make this work. You’ll need to install reattach-to-user-namespace to be able to pass through the file names.
brew install reattach-to-user-namespace
Then add the following line to your .tmux.conf
set-option -g default-command "reattach-to-user-namespace -l zsh"
Use it by running it with the sublime command as a parameter:
reattach-to-user-namespace /usr/local/bin/subl
I alias it to subl
so I can just use subl
without having to think about it.