Designing With Class: Sinatra + PostgreSQL + Heroku
Posted by baicai on April 22, 2016
September 29, 2013: bootstrap 3, jQuery, css
November 21, 2013: added the ability to edit posts, demonstarted how to escape HTML
May 4, 2014: added a captcha to the new post form to help prevent spam (see blog post here)
Know a little Ruby? Ready to start web development? Before jumping to Rails, get your hands dirty with Sinatra. It’s the perfect learning tool. My recommendation: Start with a basic dynamic website, backed with SQLite. Create and manage your database tables with raw SQL. Practice deploying on Heroku. Practice.
Once you feel good, add another step. Perhaps switch to DataMapper or ActiveRecord for managing your database with objects. Add a more complex database, such as PostgreSQL.
In this tutorial …</h2>
… we’ll be hitting the middle ground. You’ll be creating a basic blog app. Before you yawn and move on, we will be using some awesome tools/gems for rapid development:
Sinatra: the web framework, of course
PostgreSQL: the database management system
ActiveRecord: the ORM
sinatra-activerecord: ports ActiveRecord for Sinatra
Tux: provides a Shell for Sinatra so we can interact with our application
This tutorial assumes you are running a Unix-based environment - e.g, Mac OSX, straight Linux, or Linux VM through Windows. I will also be using Sublime 2 as my text editor.
Let’s get Sinatra singing!
Start by creating a project directory somewhere on your file system:
Setup your gems using a Gemfile. Create the following Gemfile (no extension) within your main directory:
Notice how we’re using SQLite3 for our development environment and PostgreSQL for production, in order to simply the dev process.
Install the gems:
This will create Gemfile.lock, displaying the exact versions of each gem that were installed.
Create a config.ru file, which is a standard convention that Heroku looks for.
Create a file called environments.rb and include the following code for our database configuration:
Next, create the main application file, “app.rb”. Make sure to include the required gems and the environments.rb file we just created.
Create a Rakefile (again, no extension) so we can use migrations for setting up the data model:
Now run the following command to setup the migration files:
If you look at your project structure. You’ll see a new folder called “db” and within that folder another folder called “migrate.” You should then see a Ruby script with a timestamp. This is a migration file. The timestamp tells ActiveRecord the order in which to apply the migrations in case there is more than one file.
Essentially, these migration files are used for setting up your database tables. Edit the file now.
The up method is used when we complete the migration (rake db:migrate), while the down method is ran when we rollback the last migration (rake db:rollback).
Run the migration
Just so you know, ActiveRecord created these table columns: id, title, body, created_at, updated_at
When you create a new post, you only need to specify the title and body; the remaining fields are generated automatically with ActiveRecord’s magic! Pretty cool, eh?
Use tux in order to add some data to the database.
Did you notice the actual SQL syntax used for each command? No? Look again.
Add a few more posts. Then exit:
Before moving on, let’s get this app under version control.
Templates and views
Add the following code to app.rb to setup the first route:
This maps the / url to the template index.html (or index.erb in Ruby terms), found in “"views/posts/” directory.
Note: The app.rb file is the controller in MVC-style architecture.
Add the helper for the title variable:
Fire up the dev server:
Then navigate to http://localhost:4567/. You should see an error indicating the template can’t be found - “/sinatra-blog/views/posts/index.erb”. In other words, the URL routing is working; we just need to set up a template.
First create two new directories - “views/posts” …
Now, setup the associated template called index.erb:
Save this file within the “posts” directory.
Now set up the layout.erb template, which is used as the parent template for all other templates. This is just a convention used to speed up development. Child templates, such as index.erb inherent the HTML and CSS (common code) from the parent template.
Save this file within the “views” directory.
The yield method indicates where templates are embedded.
Kill the server. Fire it back up. Go back to http://localhost:4567/. Refresh. You should see your basic blog. Click on a link for one of the posts. Since we don’t have a route associated with that URL, Sinatra gives us a little suggestion.
Route and template for viewing each post.
Template (called view.erb):
Route and template for adding new posts.
Template (called create.erb):
We also need a route for handling the POST requests.
Test this out. Did it work? If you get this error “Couldn’t find Post with ID=new” you need to put the last two routes above the route for viewing each post:
Validation and Flash Messages
Add some basic validation to app.rb:
So, both the title and body cannot be null, and the title has to be at least 5 characters long.
Navigate to http://localhost:4567/posts/create. Try to submit a blank post and then submit a real one. It’s a bit confusing to the user when a blank post is submitted and nothing happens, so add some messages indicating that an error has occurred.
First, add this to the top of app.rb:
Update the POST request route:
Add the following code to the layout.erb template just above the yield method:
Now test it again!
The app is ugly. Add some quick bootstrap styling.
Looking good? Well, a little better.
Alright. We need to be able to edit live posts.
Add an edit template
Update the view template
Test and Commit to Git
Yes, test to ensure you can edit posts locally, then add and commit to Git.
Currently, you can enter really anything into the input boxes for the title and body, including HTML. Test this out. Enter these code snippets in the title and/or or body:
<strong>Very, very strong</strong>
See the issue? We need to escape the text properly in order to avoid this.
Add the following helper:
Update the view template
Update the edit template
Update the index template
Now try to enter <strong>Very, very strong</strong>. Notice the difference? See this page for further explanation.
Commit to Git again.
Finally, let’s get this app live on Heroku!
Create an account on Heroku. (if needed)
Install the gem - sudo gem install heroku (if needed)