I have been seeing this question many times on the hanami chat. The hanami-controller offers as much as Rails in routing. So you get resources :posts with all accompanying routes.

# apps/web/config/routes.rb
resources :posts

# $ bundle exec hanami routes

GET     '/posts',          to: Web::Controllers::Posts::Index
GET     '/posts/new',      to: Web::Controllers::Posts::New
POST    '/posts',          to: Web::Controllers::Posts::Create
GET     '/posts/:id',      to: Web::Controllers::Posts::Show
GET     '/posts/:id/edit', to: Web::Controllers::Posts::Edit
PATCH   '/posts/:id',      to: Web::Controllers::Posts::Update
DELETE  '/posts/:id',      to: Web::Controllers::Posts::Destroy

DELETE’ing a resource

The problem I have seen mostly is because a lot of people expect it to work like in Rails. Rails is a very mature framework and a lot of nuances have been taken care of. Hanami is still getting its feet on the road and its ready for production if you are willing to write a little more code than in Rails.

The way Rails does it is by simulating a form using the POST HTTP verb. Since most browser vendors only support HTTP protocols GET, POST and PUT verbs. The DELETE verb needs a workaround. When you click a link that implements a delete action. JQueryUJS intercepts that click and presents an alert, after you confirm. The action is sent as a form post. So in the form below, your submit action is sent as a POST, the param[:_method] is used to initiate the #destroy action on your controller :

<form action="/posts/1234" method="post">
  <input type="hidden" name="_method" value="delete">
  <!-- ... -->
</form>

In Hanami however, unless you include JQueryUJS. You will have to do this manually. So lets take one of my favourite approach.

# action code
module Web::Controllers::Posts
  class Destroy
    include Web::Action

    params do
      required(:id).filled
    end.valid?

    def initialize(post: PostRepository)
      @post = post.new.find(params[:id])
      # @comments = CommentRepository.new.for_post(@post.id)
      # @user = UserRepository.new.find(@post.user_id)
    end

    def call(params)
        # redirect_to '/' unless authorize!(@user, @post)
      if @post
        @post.destroy
        redirect_to '/'
      else
        # handle error
      end
    end
  end
end

Its relatively straightforward. Now we just need to setup our route to:

DELETE '/posts/:id', to: Web::Controllers::Posts::Destroy

And this should work with or without Javascript. Now you just need to use a form to post to this action.

  form_for post, routes.post_path(id: post.id), method: :delete, class: 'uk-form' do
    submit 'Destroy', class: 'uk-button uk-button-danger'
  end

This will produce a form similar to the following:

<form id="post-form" action="/posts/1234" class="uk-form">
  <input type="hidden" name="_method" value="delete">
  <input type="hidden" name="authenticity_token"  value="f755bb0ed134b76c4" />

  <input type="submit" name="commit" value="Destroy" class="uk-button uk-button-danger" />
</form>