FormAPI Blog

Using AppleScript to set up iTerm2 for Rails Development

A Rails developer often needs to start multiple processes while working on an application. You might need to run rails server, sidekiq to process background jobs, and webpack to compile your front-end code. You’ll probably also want to have a Rails console.

iTerm2 is an excellent terminal emulator for Mac that supports tabs and panes. It also has very good AppleScript support, so you can write a script that sets up some panes and tabs, and starts some processes.

I’ve created .dev.scpt scripts in the root folder of my projects. I’ve also added a ds alias to my ~/.bashrc so that I can run them quickly:

alias ds='osascript .dev.scpt "$(pwd)"'

This shortcut runs any .dev.scpt script with the current directory as an argument.

The following AppleScript will:

  • Start rails server in the current session
  • Start sidekiq in a new pane on the bottom left
  • Start webpack in a new pane on the bottom right
  • Start rails console in a new tab
  • Open a few extra tabs for things like git, rspec, deploys, etc.
on run argv
  set current_dir to item 1 of argv

  tell application "iTerm2"
    tell current window
      set rails_session to current session
      set current_tab to current tab

      tell current session
        write text "bundle exec rails server --binding=127.0.0.1 --port 3000"

        set sidekiq_session to split horizontally with default profile
        tell sidekiq_session to select
        write text "cd " & current_dir
        write text "bundle exec sidekiq"

        set client_session to split vertically with default profile
        tell client_session to select
        write text "cd " & current_dir & "/client"
        write text "yarn run build:development"
      end tell

      # Only open some more tabs if this is a new window
      if count of tabs is 1 then
        set new_tab to create tab with default profile
        tell current session of new_tab
          write text "cd " & current_dir
          write text "rails console"
        end tell

        # Open some extra tabs for git, rspec, deploys, etc.
        repeat 3 times
          set new_tab to create tab with default profile
          tell current session of new_tab to write text "cd " & current_dir
        end repeat
      end if

      tell current_tab to select
      tell rails_session to select
    end tell
  end tell
end run

Why not run Sidekiq inline?

If you’re only using Rails and Sidekiq, you might be tempted to run your Sidekiq jobs “inline” during development:

require 'sidekiq/testing'
Sidekiq::Testing.inline!

The advantage is that you can just run rails server, instead of starting multiple processes. However, you might end up missing some bugs and edge cases that are related to asynchronous behavior. It’s always better if you can run the same code in development and production. Active Job’s default adapter was also changed from :inline to :async in Rails 5:

It’s a better default as tests will then not mistakenly come to rely on behavior happening synchronously.

Other Options

Foreman

foreman is another popular choice. You create a Procfile with all of the commands that you need to run:

web: bundle exec rails server --binding=127.0.0.1 -p 3000
worker: bundle exec sidekiq
client: cd client && yarn run build:development

Runing foreman start will start the processes:

$ foreman start
12:38:24 web.1    | started with pid 46746
12:38:24 worker.1 | started with pid 46747
12:38:24 client.1 | started with pid 46748

The problem is that you can’t use a debugger. I often use pry-byebug to debug my code by calling binding.pry, and the IRB prompt doesn’t work properly when you’re using foreman.

tmuxinator + tmux

tmuxinator sets up different tmux panes and windows to run all of your processes. A configuration file looks like this:

windows:
  - editor:
      layout: main-vertical
      panes:
        - bundle exec rails s
        - bundle exec sidekiq
        - cd client && yarn run build:development
  - logs: tail -f log/development.log

This runs each process in a different pane or window, so you can use binding.pry to debug your code. It’s also great for developers who use vim or emacs. However, it wasn’t for me. I couldn’t find a nice “prefix key” for the keyboard shortcuts. I have to stretch my hand too far for Ctrl+b, and Ctrl+a kind of hurts my wrist.

I think iTerm2 has much nicer keyboard shortcuts than tmux, because you don’t need to use a prefix key. You can also use the mouse for drag-and-drop reordering of tabs and panes, or to switch between them.


More options from the comments of our Reddit post:

overmind and hivemind

Overmind and Hivemind are process managers for Procfile-based applications, inspired by foreman. Hivemind was the initial version, but Overmind is a lot more powerful. It runs all the processes in a tmux session. This means that you can connect to the tmux session to access the debugger. You can also restart individual processes. Learn more about Overmind and Hivemind.

threeman

Another alternative to foreman for Mac users. Runs each command in a separate iTerm2 tab.

invoker

“An awesome utility to manage all your processes in development environment.” Homepage: http://invoker.codemancers.com

mux

Mux is a VS Code plugin to manage tmux sessions

pry-remote

A way to start Pry remotely and to connect to it using DRb. This allows access to the state of the running program from anywhere. You could use pry-remote to connect to a process started by foreman, in a Docker container, or even on a remote server.

iTerm2’s saved window arrangements

This article shows how you can set up a keyboard shortcut to restore a saved window arrangement in iTerm2.


Thanks for reading!

I hope this post was helpful. If you’re using a process-management tool that hasn’t been mentioned yet, please leave a comment on Reddit, or send us an email at [email protected]