Writing a CRUD-y sinatra app that you can deploy to Heroku
Tags: ruby, webdev, heroku, sinatra
Published: 2023-10-27 21:09:37

This article was written by AI, be forewarned that it may not be 100% accurate for your purposes, but it did work for mine.  Let me know if you see anything that needs to be corrected!

---

## Building a Sinatra CRUD App for Recipes with SQLite3

Want a simple Sinatra CRUD app for recipes? This guide walks you through setting up Sinatra, connecting to SQLite3, and creating routes for basic CRUD operations.

### Setup:

1. **Gem Installation**: Install the required gems:
```bash
gem install sinatra sinatra-activerecord sqlite3
```

2. **Project Structure**: Set up your basic directory structure:
```
/myapp
  /models
  /views
  /public
  app.rb
  config.ru
  Gemfile
  config
    /database.yml
```

3. **Gemfile**: Add the required gems:
```ruby
source 'https://rubygems.org'

gem 'sinatra'
gem 'sinatra-activerecord'
gem 'sqlite3'
```

Then, run `bundle install`.

4. **Database Configuration (`config/database.yml`)**:
```yaml
development:
  adapter: sqlite3
  database: db/development.sqlite3
```

### Model:

Create a model for your recipes (`models/recipe.rb`):

```ruby
class Recipe < ActiveRecord::Base
end
```

### Migrations:

Generate and run a migration to create the `recipes` table:

1. Generate: 
```bash
rake db:create_migration NAME=create_recipes
```

2. Define the migration (`db/migrate/[timestamp]_create_recipes.rb`):
```ruby
class CreateRecipes < ActiveRecord::Migration[6.0]
  def change
    create_table :recipes do |t|
      t.timestamps
      t.datetime :deleted_at
      t.string :name, unique: true
      t.text :content
    end
  end
end
```

3. Run the migration:
```bash
rake db:migrate
```

### Sinatra App (`app.rb`):

Here's a stripped-down version of your CRUD operations:

```ruby
require 'sinatra'
require 'sinatra/activerecord'
require_relative 'models/recipe'

# List all recipes
get '/recipes' do
  @recipes = Recipe.all
  erb :index
end

# Create a new recipe
post '/recipes' do
  Recipe.create(params[:recipe])
  redirect '/recipes'
end

# Delete a recipe (soft delete)
delete '/recipes/:id' do
  @recipe = Recipe.find(params[:id])
  @recipe.update(deleted_at: Time.now)
  redirect '/recipes'
end

# ... [other CRUD operations]
```

### Views:

1. **Listing Recipes (`views/index.erb`)**:
```erb
<h1>Recipes</h1>
<ul>
  <% @recipes.each do |recipe| %>
    <li>
      <a href="/recipes/<%= recipe.id %>"><%= recipe.name %></a>
      <form action="/recipes/<%= recipe.id %>" method="post" onsubmit="return confirm('Are you sure?');">
        <input type="hidden" name="_method" value="delete">
        <input type="submit" value="Delete">
      </form>
    </li>
  <% end %>
</ul>
<a href="/recipes/new">Add New Recipe</a>
```

2. **New Recipe (`views/new.erb`)**:
```erb
<h1>New Recipe</h1>
<form action="/recipes" method="post">
  <div>
    <label for="name">Name:</label>
    <input type="text" id="name" name="recipe[name]">
  </div>
  <div>
    <label for="content">Content:</label>
    <textarea id="content" name="recipe[content]"></textarea>
  </div>
  <input type="submit" value="Create Recipe">
</form>
```

### Running:

1. Start your Sinatra app:
```bash
ruby app.rb
```

2. Access the app via `http://localhost:4567/recipes`.

---

That's a basic walkthrough of creating a Sinatra app with SQLite3 to manage recipes. Adjust, expand, and modify it as you see fit, and happy coding!