HanamiMastery

Listing articles in Hanami and Dry-View

Episode #2

by Sebastian Wilgosz

Picture of the author

In the previous episode, I've created a new Hanami application, using the Template repository.

At the moment, It only has the home page implemented, but I'd love to transfer it into a blog application. In this episode, I'll show you how to list the objects in the Hanami template. We will focus on understanding the Hanami::View part of the architecture.

To start, let's start by adding a new route, under the /articles URL.

Adding static HTML rendering endpoint

First, let's visit the routes.rb file stored in the config directory. The router distributes the incoming requests and decides which action should handle that.

So let's add a route to handle get requests to /articles URL and write the handler to it. The handler in Hanami can be literally anything that responds to a call method, accepting the rack env as an argument, and returning the serialized rack response, so for a very minimal example, we can even use a raw proc.

# /config/routes.rb

Hanami.application.routes do
  slice :main, at: "/" do
    root to: "home.show"

    get '/articles', to: ->(env) { [200, {}, ['<h1>Articles</articles>']] }
  end
end

This will render the level one header HTML tag with the Articles string in the browser.

Static Page renderingStatic Page rendering

Rendering

This is super simple and elastic in use because as those are the only requirements, we can replace this proc with any object that meets the router's expectations!

If we'd have to render more complicated templates, however, it'd be nice to have a class that takes care of preparing the HTML to keep our routes clean and simple.

This is when Hanami/Action comes in. I can replace the proc written directly in the routes with a path pointing into the action I want to call instead.

# /config/routes.rb

Hanami.application.routes do
  slice :main, at: "/" do
    root to: "home.show"

    # get '/articles', to: ->(env) { [200, {}, ['<h1>Articles</articles>']] }
    get '/articles', to: "blog.articles"
  end
end

By default, Hanami assumes that actions for a given slice are placed in the actions folder inside this slice, and the rest of the path matches what we've written in the route.

Let me then create a new action named articles, in the blog folder.

Remember: It can be any ruby object, that responds to a call, accepting rack env as an argument and returning the rack response.

So let's define the call method, and return the standard rack response, but with a different string in the h1 tag, just to be sure it works.

# /slices/main/lib/main/actions/blog/articles.rb

module Main
  module Actions
    module Blog
      class Articles
        def call(env)
          [200, {}, ['<h1>Articles rendered by class</h1>']]
        end
      end
    end
  end
end

Now when I'll visit the browser, You should see the updated text. Awesome!

Note: If you're trying it out before the Hanami 2.0 is officially released, you may need to restart the server!

Static Page renderingStatic Page rendering

Using views and templates

While this works fine, usually we'd like to write our templates in the html or slim files or serialize our JSON responses using serializers instead of using raw strings everywhere.

This is why in Hanami, except actions, we have also views and templates.

Static Page renderingStatic Page rendering

The whole request flow starts from the router, then it's distributed into proper action.

  • Action parses the request to extract the params and headers. The action then calls the proper view object with prepared arguments.
  • The view, based on the given arguments, prepares data for template to render, and then renders the proper template with certain local variables exposed.
  • The template, however, only specifies, how the structure of the rendered document looks like. Then it's rendered by a view.

Having this in mind, let's leverage this architecture, starting by using the Hanami::Action.

When I'll remove the custom call method and inherit from the Main::Action, it'll look for a specific view and try to call it with the prepared parameters.


# /slices/main/lib/main/actions/blog/articles.rb

module Main
  module Actions
    module Blog
      class Articles < Main::Action
      end
    end
  end
end

Please notice that we inherit here for action specific for the given slice - as there may be a situation, where each slice will have a different authorization strategy or other request transformations.

Now let's create a template for the article listing of our blog. I create the articles.html.slim template file in the templates directory and inside let's list some articles' titles.

# /slices/main/web/templates/blog/articles.html.slim

h1 Blog articles

ul
  - articles.each do |article|
    li = article.title

Then I need a view that will render this template, which will be stored under the same path in the views directory of the main slice.

# /slices/main/lib/main/views/blog/articles.rb

Article = Struct.new(:title)

module Main
  module Views
    module Blog
      class Articles < View::Base
        expose :articles do
          %w[article1 article2 article3].map do |title|
            Article.new(title)
          end
        end
      end
    end
  end
end

Within the view lays the logic of preparing the data for a template. My template need articles collection that it can iterate by, so let's quickly expose articles method, and generate a simple array of structs to be returned.

I need the article definition yet, and we're ready to go! A quick look at the browser, and Voila! Here are our articles listed!

Static Page renderingStatic Page rendering

This is still just a rendering - to style it up you'll need to make use of Hanami::Assets which I cover in the next episode

Summary

In this episode, we've gone through the basic rendering flow in Hanami applications and understood the view-related part of Hanami Architecture.

It may be a lot compared to the simplified, MVC approach, where there are only three parts of the system - Model, View, and Controller, but history proved that MVC just does not scale well.

The extended Hanami architecture, where each class has its dedicated purpose definitely allows to reduce coupling in bigger systems and helps to better manage complexity.

Special Thanks

Do you know great Ruby gems?

Add your suggestion to our discussion panel!

I'll gladly cover them in the future episodes! Thank you!

Suggest topicTweet #suggestion

May also interest you...

#53 Advanced forms in Hanami 2
viewshanami

Working with templates is a hard job and eliminating the logic out of them is absolutely not trivial. In this episode we'll use Hanami tools to implement advanced forms.

Showing flash messages in Hanami is trivial, and it is even shown in the official guides. In this episode though, we make this future-proof, testable, and maintainable for a future growth of your application.

Probably any web app nowadays requires font icons to be loaded this or other way. In this episode, I'm showing the integration of Font Awesome icons in Hanami 2 applications.

There is a famous video about the IT skill iceberg - but thankfully, there is an alternative. If you ever wondered if you can build entire websites without HTML overhead, now you can! Meet Phlex, a view engine, where you can write Ruby instead of HTML

Coffee buy button
Trusted & Supported by
AscendaLoyalty

1 / 1
Open Hanami Jobs

We use cookies to improve your experience on our site. To find out more, read our privacy policy.