simple-sinatra-mvc

Simple Sinatra MVC Template

Build Status Code Climate

This Sinatra project template supports Ruby 3.0. There is no guarantee that the template still works for older versions, but it should work for the latest version of Ruby.

What’s included

Table of contents

Getting Started

git clone --depth 1 git://github.com/kathgironpe/simple-sinatra-mvc.git myapp

Installation

This usually works on Mac/Linux. For Windows users, you may have to try chocolatey to install dependencies.

Install Ruby 3.1 or greater

Through asdf or rbenv, please install Ruby 3.1 or greater.

Using Homebrew and Rbenv to install Ruby:

Install Rbenv if you don’t have it:

brew update
brew install rbenv
rbenv init

Install Ruby 3.1.0 or greater. The current version is actually 3.2.0.

brew update && brew upgrade ruby-build
rbenv install 3.1.0
rbenv global 3.1.0

Using asdf to install Ruby:

asdf plugin-add ruby
asdf install ruby latest
asdf global ruby latest

Install Node.js via asdf

asdf plugin-add nodejs
asdf install nodejs latest
asdf global nodejs latest

If you encounter an OpenSSL error when running webpack, run this first:

export NODE_OPTIONS=--openssl-legacy-provider

webpack

Use bundler to install gems

gem i bundler
bundle install --no-deployment

Use npm to install some dependencies

npm i

Start the server

rackup

Configuration

$ cp config/database.yml.example config/database.yml

Update database.yml.

By default, we use PostgreSQL.

To install PostgreSQL on a Mac, you might need homebrew.

brew install postgresql

Creating a database should be as simple as:

createdb database_name

The rake task for creating the database also works:

rake db:create

This works because the default Rack environment is development.

If the commands fail, your config file may be incorrect

Normally, you already have a postgres user with a blank password. Otherwise, please refer to the PostgreSQL documentation and create a new user.

The default port is 5432. Please verify all settings on config/database.yml are correct before running any rake tasks.

You may have to update config.ru and files on config directory as needed.

Rake Tasks

$ rake -T

This returns this output:

rake db:create              # Creates the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:create:all to create all databases i...
rake db:create_migration    # Create a migration (parameters: NAME, VERSION)
rake db:drop                # Drops the database from DATABASE_URL or config/database.yml for the current RAILS_ENV (use db:drop:all to drop all databases in the ...
rake db:encryption:init     # Generate a set of keys for configuring Active Record encryption in a given environment
rake db:environment:set     # Set the environment value for the database
rake db:fixtures:load       # Loads fixtures into the current environment's database
rake db:migrate             # Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)
rake db:migrate:down        # Runs the "down" for a given migration VERSION
rake db:migrate:redo        # Rolls back the database one migration and re-migrates up (options: STEP=x, VERSION=x)
rake db:migrate:status      # Display status of migrations
rake db:migrate:up          # Runs the "up" for a given migration VERSION
rake db:prepare             # Runs setup if database does not exist, or runs migrations if it does
rake db:reset               # Drops and recreates all databases from their schema for the current environment and loads the seeds
rake db:rollback            # Rolls the schema back to the previous version (specify steps w/ STEP=n)
rake db:schema:cache:clear  # Clears a db/schema_cache.yml file
rake db:schema:cache:dump   # Creates a db/schema_cache.yml file
rake db:schema:dump         # Creates a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`)
rake db:schema:load         # Loads a database schema file (either db/schema.rb or db/structure.sql, depending on `config.active_record.schema_format`) into the d...
rake db:seed                # Loads the seed data from db/seeds.rb
rake db:seed:replant        # Truncates tables of each database for current environment and loads the seeds
rake db:setup               # Creates all databases, loads all schemas, and initializes with the seed data (use db:reset to also drop all databases first)
rake db:version             # Retrieves the current schema version number
rake spec                   # Run RSpec code examples

To create a database for a specific environment, do:

rake db:create RACK_ENV=production

The default environment is “development”

To create a migration file called “create_pages”, do:

rake db:create_migration NAME=create_pages RACK_ENV=production

To run the migration and create the tables:

rake db:migrate RACK_ENV=production

To rollback:

rake db:rollback RACK_ENV=production

The default Rack environment is development so this should just work:

rake db:migrate

To start the server, use rackup:

rackup

When you have to deploy this, the processes have to be daemonized like so:

rackup -D

Examples

For those still learning Sinatra basics, you might want to generate the example data for the posts route:

bundle exec rake examples

You should see something like this:

Creating examples for development environment
There are already 20 posts created

Start the app with rackup and visit http://localhost:9292/posts

Testing

Unit tests for Ruby

Use RSpec for unit tests and functional tests.

To get started, you need to create the database for tests.

bundle exec rake db:create RACK_ENV=test

Prepare the database like you would do in a Rails application:

 bundle exec rake db:test:prepare RACK_ENV=test

Verify that RSpec works without issues:

bundle exec rake spec

Unit tests for TypeScript

TypeScript files are tested by creating a new file like app.test.ts.

Run unit tests for Typescript simply using:

jest

Or a long version:

npm run test:js

Integration tests

Cucumber is likely still widely used, but Cypress is more widely-used for testing front-end.

To write a new integration test, you must check the cypress directory for examples.

To install cypress:

cypress install

To run the tests, do:

npm run cypress:open

GitHub Actions

This repo uses GitHub actions for running tests. You can reuse the workflow files for your project.

Asset Pipeline

As a 7-year-old project as of April 2021, I have changed my mind many times about asset management. From Sprockets to Brunch.js and now Webpack.js, the changes are largely based on experience and community support. Using Webpack makes sense for asset management. Currently, even Ruby on Rails uses this.

By default, we have the following supported directories:

Your non-JavaScript and non-CSS files should go to app/assets/files directory.

Why Webpack?

Used and trusted by a lot. The documentation is very clear.

Configuring Webpack

Please take some time to read the documentation before updating webpack.config.js.

Using TypeScript

Currently, this is likely the only dependency that does not make this project simple. The learning curve isn’t high enough. It is just a subset of JavaScript. There are proposals of having types and interfaces for JavaScript, but there are still TypeScript features that are valuable for developers.

There is no assumption that you will build a single-page application when you use this project. I can imagine it could be more simple like a blog site with nearly no JavaScript. TypeScript could help you write better code.

TS Lint

ESLint is configured to support TypeScript primarily. You can configure your editor to fix issues on save. I highly recommend using VSCode.

To check for TypeScript syntax and other errors on your code, run:

npm run ts:lint

You can auto-fix many issues using:

npm run ts:lint-fix

Using Tailwind

Styles using SCSS and Tailwind are compiled by running:

npm run build:css

Security

By default Sinatra already has security headers without you do a lot of this. In other Ruby frameworks, these may not exist for a reason:

curl --head  http:\/\/localhost:9292
HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
Content-Length: 11910
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Vary: Accept-Encoding
Connection: keep-alive

Please refer to OWASP site to learn what each security header means.

You may use the helpers for sanitizing text like h and hattr. You may also write your own helper.

Pre-deployment

Review Gitignore file

You likely have to remove some entries on the .gitignore file like config/database.yml if you are deploying on Heroku or OpenShift.

Deployment Guides

Deployment to Heroku and OpenShift should fairly be easy. We rely on postinstall on package.json to build the assets. Regardless of where you deploy your app, you need the following installed:

  1. Node.js
  2. Latest stable Ruby version

The command npm install or npm i will install Node.js packages and build the assets using brunch.

Heroku

Deploying a Sinatra or Ruby on Rails application on Heroku requires some buildpacks.

heroku buildpacks                     # view current buildpacks
heroku buildpacks:clear               # clear current buildpacks, if necessary
heroku buildpacks:add heroku/nodejs   # add the Node.js buildpack
heroku buildpacks:add heroku/ruby     # add the Ruby buildpack

You generally don’t have to worry about building the assets as long you have the same package.json on this repository. Please read build, postinstall, and deploy scripts.

Other necessary steps: please read pre-deployment.