Implementing GET POST PUT DELETE with Ruby Sinatra

Run the App!

Let's get down to the brass-ier tacks of building a client-server HTTP based programming !!

  git clone git@github.com:jcdavison/fundamentals_of_web_programming.git
  cd fundamentals_of_web_programming
  cd spriggly-wiggly/
  bundle install
  bundle exec rerun 'ruby spriggly_wiggly_web_app.rb'
  #  woohoo !!

We are going to build a handful of features in a sequenced order :)

Snippets of code are located inside

  /fundamentals_of_web_programming/spriggly-wiggly/building_blocks

Build Restaurant and Order object models

  require 'data_mapper'

  DataMapper.setup(:default, 'sqlite:spriggly-wiggly.db')

  class Restaurant
    include DataMapper::Resource

    property :id, Serial
    property :location, Text, required: true
    property :name, Text, required: true 

    has n, :orders, :constraint => :destroy  
  end

  class Order
    include DataMapper::Resource

    property :id, Serial
    property :description, Text, required: true
    property :restaurant_id, Integer, required: true

    belongs_to :restaurant
  end

  DataMapper.finalize()
  DataMapper.auto_upgrade!()
  irb -r './spriggly_wiggly_web_app.rb'
  Restaurant.new
  Order.new

  # create some new restaurants
  # create some new orders with restaurant_ids that map to known restaurants

Implement /

  # Enable the root server endpoint
  get('/') do
    restaurants = Restaurant.all
    erb(:index, locals: { restaurants: restaurants })
  end
  <%# all restaurants %>
  <% restaurants.each do |restaurant| %>
    <div class='restaurant-display-tile'>
      <p> Restaurant id: <%= restaurant.id %> '<%= restaurant.name %>' located at '<%= restaurant.location %>' </p>
      <p>has <%= restaurant.orders.count %> order(s).</p>
    </div>
  <% end %>

Add some styles so that things look 'better' :)

  /* assign a font and color to various html elements*/ 
  p, h1, h2, h3, h4, ul, li, a {
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    color: #157DA6;
    text-align: center;
  }

  /* various css class definitions that allow for general styling */

  .centered {
    text-align: center;
  }

  .restaurant-display-tile {
    border: 3px solid #75c196;
    border-radius: 5px;
    margin: 10px auto;
    padding: 10px;
    width: 50%;
  }

  .super-sport {
    background-color: white;
    border: 1px solid #157DA6;
    border-radius: 5px;
    cursor: pointer;
    color: black;
    font-size: 12px;
    font-weight: normal;
    text-decoration: none;
    padding: 5px;
  }

  .inline {
    display: inline;
  }

  .pull-right {
    float: right;
  }

  .action-tile {
    border: 3px solid #c14436;
    border-radius: 5px;
    margin: 10px auto;
    padding: 10px;
    width: 50%;
  }

Implement POST /restaurants

  # render the new restaurant form
  get('/restaurants/create') do
    erb(:create_restaurant)
  end
  <%# a form that can create a new restaurant%>
  <form action='/restaurants' method='POST' class='centered'>
    <label>name</label>
    <input type='text' name='name' required/>
    <label>location</label>
    <input type='text' name='location' required/>
    <input type='submit' value='create new restaurant' />
  </form>
  # create a new restaurant
  post('/restaurants') do
    new_restaurant = Restaurant.new
    new_restaurant.name = params[:name]
    new_restaurant.location = params[:location]
    new_restaurant.save
    redirect('/')
  end

Implement PUT /restaurants

  # render the restaurant of concern
  get('/restaurants/:id/edit') do
    restaurant = Restaurant.get(params[:id])
    render(:edit_restaurant, locals: { restaurant: restaurant })
  end
  <%# a form that edits an existing restaurant %>
  <form action='/restaurants/<%= restaurant.id %>' method='POST' class='centered'>
    <label>name</label>
    <input type='text' name='name' required value='<%= restaurant.name %>' />
    <label>location</label>
    <input type='text' name='location' value='<%= restaurant.location %>' required/>
    <input type='hidden' name='_method' value='PUT'>
    <input type='submit' value='edit restaurant' />
  </form>
  # update a restaurant
  put('/restaurants/:id') do
    restaurant = Restaurant.get(params[:id])
    restaurant.name = params[:name]
    restaurant.location = params[:location]
    restaurant.save
    redirect('/')
  end

Implement DELETE /restaurants/:id

  <%# a form that deletes an existing restaurant%>
  <form action='/restaurants/<%= restaurant.id %>' method='POST' class='pull-right'>
    <input type='hidden' name='_method' value='DELETE'/>
    <button type='submit' class='super-sport'>X</button>
  </form>
  # delete restaurant
  delete('/restaurants/:id') do
    Restaurant.get(params[:id]).destroy
    redirect('/')
  end

Render a Restaurant's Orders

  <%# all orders for an individual restaurant %>
  <% restaurant.orders.each do |order| %>
    <h4>
      Order id: <%= order.id %> is '<%= order.description %>'
    </h4>
  <% end %>

Implement POST /orders

  # a form element to create a new order for a restaurant
  <form action='/orders' method='POST' class='centered' >
    <input type='text' name='description' required />
    <input type='hidden' name='restaurant_id' value='<%= restaurant.id %>'>
    <input type='submit' value='create order' class='super-sport'>
  </form>
  # create a new order
  post('/orders') do
    new_order = Order.new
    new_order.description = params[:description]
    new_order.restaurant_id = params[:restaurant_id]
    new_order.save
    redirect('/')
  end

Implement PUT /orders

  # render order to be edited
  get('/orders/:id/edit') do
    order = Order.get(params[:id])
    erb(:edit_order, locals: { order: order })
  end
  <%# a link to visit a page that will render an update order form %>
  <a href='/orders/<%= order.id %>/edit' class='super-sport'>edit order</a>

  <%# a form to update an existing order %>
  <form action='/orders/<%= order.id %>' method='POST' class='centered'>
    <label>description</label>
    <input type='text' name='description' required value='<%= order.description %>' />
    <input type='hidden' name='_method' value='PUT'>
    <input type='submit' value='edit order' />
  </form>
  
  # update an order
  put('/orders/:id') do
    order = Order.get(params[:id])
    order.description = params[:description]
    order.save
    redirect('/')
  end

Implement DELETE /orders/:id

  <%# a form that allows an order to be destroyed %>
  <form action='/orders' method='POST' class='inline' >
    <input type='hidden' name='order_id' value='<%= order.id %>'>
    <input type='hidden' name='_method' value='DELETE'>
    <input type='submit' value='destroy order' class='super-sport'>
  </form>
  # delete order
  delete('/orders') do
    order_to_delete = Order.get(params[:order_id])
    order_to_delete.destroy
    redirect('/')
  end
I continually seek new software engineering contracts and product collaboration opportunities so please, send email to jd@startuplandia.io.