Getting Started

Install Terminalwire in a Rails app and build your first terminal

This guide assumes you have Ruby and Rails installed on your workstation.

Create a Rails app

If you don’t already have a Rails app, create one.

rails new my-app
cd my-app

Install Terminalwire in Rails

Add the Terminalwire Rails gem to your app.

bundle add terminalwire-rails

Then install Terminalwire in your Rails app.

rails g terminalwire:install my-app

Configure the terminal

The rails g terminalwire:install my-app command creates files that you may configure for your application’s needs.

Terminal command-line classes

The ./app/terminals folder contains two files that define your command-line interface.

ApplicationTerminal

The application_terminal.rb file is the base class for your terminal application. It includes the Terminalwire::Thor module to enable I/O streaming, sets the basename for help output, and provides helper methods like current_user for authentication.

# ./app/terminals/application_terminal.rb

class ApplicationTerminal < Thor
  # Enables IO Streaming.
  include Terminalwire::Thor

  # The name of your binary. Thor uses this for its help output.
  def self.basename = "my-app"

  private

  def current_user=(user)
    # The Session object is a hash-like object that encrypts and signs a hash that's
    # stored on the client's file system. Conceptually, it's similar to Rails signed
    # and encrypted client-side cookies.
    session["user_id"] = user.id
  end

  def current_user
    @current_user ||= User.find(session["user_id"])
  end
end
MainTerminal

The main_terminal.rb file is where you define your application’s commands. You can add, remove, or modify commands as needed. This file inherits from ApplicationTerminal to access I/O streaming and authentication features.

# ./app/terminals/main_terminal.rb

class MainTerminal < ApplicationTerminal
  desc "hello NAME", "say hello to NAME"
  def hello(name)
    puts "Hello #{name}"
  end

  desc "login", "Login to your account"
  def login
    print "Email: "
    email = gets.chomp

    print "Password: "
    password = getpass

    # Replace this with your own authentication logic; this is an example
    # of how you might do this with Devise.
    user = User.find_for_authentication(email: email)
    if user && user.valid_password?(password)
      self.current_user = user
      puts "Successfully logged in as #{current_user.email}."
    else
      puts "Could not find a user with that email and password."
    end
  end

  desc "whoami", "Displays current user information."
  def whoami
    if self.current_user
      puts "Logged in as #{current_user.email}."
    else
      puts "Not logged in. Run `#{self.class.basename} login` to login."
    end
  end

  desc "logout", "Logout of your account"
  def logout
    session.reset
    puts "Successfully logged out."
  end
end

These commands use Thor, a Ruby command-line parser. You’ll learn more about defining commands, arguments, and options in the Command-Line Parsers chapter.

Routes configuration

The ./config/routes.rb file mounts the MainTerminal in a Terminalwire::Thor::Server WebSocket server to the /terminal endpoint. This is the URL your client will connect to.

# ./config/routes.rb
Rails.application.routes.draw do
  match '/terminal',
    to: Terminalwire::Thor::Server.new(MainTerminal),
    via: [:get, :connect]
end

Terminalwire binary stub configuration

Terminalwire generates a binary stub in the Rails ./bin folder that you may use to interact with your application in a development environment. You may need to change the host if the server is running on a different port.

!/usr/bin/env terminalwire-exec
url: "ws://localhost:3000"

Test the integration

To test the integration, restart your Rails server, then run ./bin/my-app hello World in your terminal and you should see the following:

./bin/my-app hello World
Hello World

You can also view all available commands by running:

./bin/my-app help
Commands:
  my-app hello NAME      # say hello to NAME
  my-app help [COMMAND]  # Describe available commands or one specific command
  my-app login           # Login to your account
  my-app logout          # Logout of your account
  my-app whoami          # Displays current user information

Congratulations, you’ve successfully built a Terminalwire command-line application! 🎉

Next steps

At this point you could deploy it to production and distribute it to your users, but first you’ll want to learn how to build more powerful command-line interfaces.

Continue to the next chapter to learn about Command-Line Parsers, where you’ll discover how to define commands with arguments and options, create subcommands, and customize help output.