Getting Started with Sinatra

By Allison Clemens | Developer

Introduction

The goal of this series will be to take a dive into the Ruby web framework Sinatra, and try to discover what it has to offer. Over the course of this journey, I will also be delving into some of the interesting features of the Ruby language and how they can be utilized to build something (hopefully) pretty cool.

Why Ruby??

Does anyone even use Ruby? When I first stated getting into learning Ruby, it seemed like no one else I knew had ever even considered using or learning it. In their defense, I can kind of see why. It is not a very popular language in the local area (unless you are already a part of the Ruby community - also sometimes referred to as more of a Ruby cult), and trying to figure out how to get started learning it can be a daunting task. My first real taste of Ruby was a head-first dive into building a Rails application from the ground up - and it was not a fun time for me. At that time, I had little understanding of MVC applications, barely any experience with basic Ruby, and had been given a few weeks to build something useful - yikes. I spent many hours banging my head against the wall trying to figure out even the most basic aspects of the Rails framework. It is a very powerful framework that takes a lot of the work off of your hands and completes it in the background for you. While this can be great, when you don’t understand what it is doing or how to properly work with it, it can cause some major confusion and frustration. Yet, even amongst all of this frustration and confusion, somehow I still found myself going back to Ruby and attempting to complete coding challenges (on codewars.com - go check it out if you haven’t, it is a ton of fun) with it rather than any other languages I had more experience with. But why? It was so fun for me because I genuinely liked the Ruby language. It provides so much that many other languages just can’t do as smoothly, especially when it comes to string operations, array manipulation, and general readability. Take the following for example: Both snippets of code below take in an integer as a argument and return it with its digits in descending order.

Java

import java.util.Comparator;
import java.util.stream.Collectors;

public class DescendingOrder {
    public static int sortDesc(final int num) {
        return Integer.parseInt(String.valueOf(num)
                                  .chars()
                                  .mapToObj(i -> String.valueOf(Character.getNumericValue(i)))
                                  .sorted(Comparator.reverseOrder())
                                  .collect(Collectors.joining()));
    }
}

While technically this could be considered just one line, the same task can be achieved in Ruby in a much simpler syntax, with no additional libraries/packages needed.

Ruby

def descending_order(n)
  n.to_s.split("").sort.reverse.join.to_i
end

Converting back and forth between data types is really easy in Ruby because it is a dynamically typed language. This makes the operations above simpler and much easier to read. While it looks like a lot going on in one line of code, I still find it easier to grasp than the similarly formatted Java code. This just shows one example of what Ruby can do to simplify the code you have to write. Here is just one more example of how easy it is to work with arrays in Ruby. The following code takes in an array, a number, and a multiplier and returns whether or not the sum of the values in the array, when multiplied by the multiplier, equals the number.

def does_it_equal( array, multiplier, number )
  array.map!{ |val| val.to_i*multiplier }.inject(:+) == number
end

Array operations in Ruby are pretty easy because the syntax for the different operations is basically the same. Adding, removing, selecting, and iterating over arrays all follow the same basic format, which makes writing code faster because it is easier to remember everything.

The syntax of Ruby made it so easy for me to solve problems quickly, without having to remember a ton of syntax, classes, and rules. So this got me thinking about how I could actually utilize Ruby outside of simply completing some programming challenges. With a bad taste from Rails still in my mouth, I started looking into other frameworks and applications that utilized Ruby as their primary language. Among the large selection of them, I decided that Sinatra would be a good one to start with, as it seemed to be a much more light weight version of Rails, built for the purpose of quickly creating web applications in Ruby with minimal effort (who doesn’t like minimal effort?). So, after this quite lengthy introduction, I finally get to the main point of this blog series. In this post I will be journaling the very beginning of my journey with Sinatra and Haml, and in future posts I hope to dive more into some cool things that I am able to build with it. Along the way, I may also try to convince you how great Ruby is and get you wishing that your preferred language has some of the things that Ruby offers (Check out this entertaining Guide to Ruby if you are already intrigued).

Getting Set Up

After creating an empty folder for the project to live in, the first step necessary to getting going was to make sure I had Ruby installed on my machine. Since I am running Windows, I used the Ruby Installer, but there are other options that may be recommended if you are running a different OS. Once Ruby was installed, I installed the gems that I would need to get a Sinatra application going (Gems are Ruby’s version of code libraries that you can install, similar to node modules). Ruby versions >=1.9 come with RubyGems (Ruby’s version of npm), but if you already have a version that is older, you may need to install RubyGems as well before moving on. Running gem install sinatra from a terminal window did the job of getting Sinatra installed. However, I realized that this simply installed Sinatra locally to my Ruby instance, and did not associate it to any specific project. Since I didn’t plan on working on this project in any other environment, this wasn’t a major concern, but from past experiences with npm, I guessed that it would probably not be best practice and decided to look into ways to install gems for a specific project.

Bundler

In my search for a solution to the gem installation, I came across Bundler. Getting Bundler installed and set up was just as easy as installing the gems, so I took the few extra steps to make sure I could create a consistent environment for my application. The first step was to install bundler with ‘gem install bundler’. After getting errors, I realized it was because I already had bundler installed (‘gem list’ shows all gems you already have). After that, all I had to do was create a Gemfile that would keep track of the project’s dependencies. Since I knew I also planned to use Haml later in the project, my basic Gemfile looked like this:

source 'https://rubygems.org'
gem 'haml'
gem 'sinatra', '~> 2.0.0'

This file has to get saved in the root project directory as ‘Gemfile’ with no extension (If you try to save it as an .rb file because that is what you saw somewhere on the internet, it will not be able to find it and will not install your gems). Once I got that all sorted out, all I had to do was run ‘bundle install’, and all of the project dependencies were installed!

Creating a Basic Application

Getting a basic application up and running was extremely easy to do, requiring just one file and only a few lines. The basic setup looks something like this:

require 'sinatra'

get '/' do
  "Hello from my first Sinatra App!"
end

Yep, that’s it! After saving this in my project’s root directory as myapp.rb, all I had to do was run ‘ruby myapp.rb’ and my application was ready on localhost:4567!

Since this was so easy, I wanted to add another route to test out path parameters. I found a couple of different ways to use path parameters, but I decided to use the one that was easiest for me to understand and simple to use for just one parameter:

get '/greeting/:name' do |name|
  "Waaazzzzzuuuuuuppp #{name}?!"
end

This shows a very basic example of using a path with just one parameter, but there are many other options for ways to handle multiple parameters that I plan to try in the future, including optional parameters, query parameters, and even route matching with Regular Expressions (check out some more of the options on the Sinatra Documentation if you want to see more).

Conclusion

I have decided to leave it at that for this time, since I have already gone on for quite a while here. Next time, I plan to get the views set up with Haml templates, and try to figure out how to properly inject variables into them. I am really enjoying the simplicity of Sinatra and how straightforward everything has been. I can not tell yet if Sinatra would lose this simplicity when scaling to a larger project, but so far it seems pretty easy to scale. Stay tuned to see more of what I am able to build with Sinatra and Haml in future posts.

Written on February 27, 2018