Building a Web Application Without Rails : Building Dynamic Views

July 9, 2022   • no-rails-app

This is the third post in the series on building a web application without using Rails. In the last post, we saw how to serve static files from our rack-based application. In this post, we will dynamically render the view template using the erb gem.

At the end of this post, our application should be able to render the data passed in the query parameters.

Dynamic Page Demo

In a typical Rails application, the following actions take place when you request a dynamic web page:

  1. The controller interacts with the model to build the data that needs to be displayed.
  2. The controller passes the generated data to the view template via instance variables.
  3. The view template uses the data to render the final view HTML to the user.

In other words, the controller layer gets what it needs from the model layer and hands it off to the view layer.

The way Rails implements controller-to-view data handoffs is through instance variables. Typically, a controller action initializes one or more instance variables used by the view.

Let’s implement a similar structure for our application.

Step 1: Replace views with view templates

As of now, our view is a static HTML. That means, each time the page loads, it renders the same HTML, no matter what. We want a dynamic view, i.e., a view which can embed variables in it, to render different view each time a page is loaded.

For this, we need a view template. We will use the erb gem used by Rails for our view templates. For learning more about the erb syntax, check out these Rails guides.

To convert the static view into a view template,

  1. Change the name of the index.html file to index.html.erb which is a view template.
  2. Update the <h1> tag to use a title variable instead of a hard-coded string.
<html>
  <head>
    <title>Application</title>
    <link rel="stylesheet" href="/public/style.css">
    <meta charset="utf-8">
  </head>

  <body>
    <main>
      <h1>
        <%= title %>
      </h1>
    </main>
  </body>
</html> 

The next question is, how to pass this title variable to the view from the app.rb file? For this, we will use the erb gem.

Step 2: Compile the views using the erb gem

This gem allows you to add any Ruby code to a plain text document for dynamically generating a new document. I recommend reading its documentation.

Here’s how it works in its essence.

require 'erb'

name = 'Akshay'
age = 30

template = ERB.new 'My name is <%= name %> and I am <%= age %> years old'
template.result(binding)

=> "My name is Akshay and I am 30 years old"

The Kernel#binding method returns a Binding object that wraps the current context, i.e. variables, methods, self along with the other information at any given time in the code for a later use.

The above code creates an instance of the ERB class with a template string. The result method on this object takes a Binding object, which we get by calling the binding method. Finally, it uses the variables defined in that binding object to render the final text.

Let’s use the above structure to render the template from the app.rb file:

require 'erb'

class App
  def call(env)
    headers = { 'Content-Type' => 'text/html' }

    return [200, headers, ['favicon']] if env['PATH_INFO'] == '/favicon.ico'

    title = 'Rack with Rails'
    template = ERB.new template_html
    response_html = template.result binding

    [200, headers, [response_html]]
  end

  def template_html
    File.read 'views/index.html.erb'
  end
end

Now reload the browser. If everything worked, you should see our (new) title on the page. That means, our application is dynamically generating views using the variables.

Dynamic View

Make it Dynamic

Now you might have questions about the dynamic nature of the above code. We are still using the hard-coded string “Rack with Rails”. But the important part is that we are fetching the value from the title variable. Now that value can come from anywhere, which is the part that makes it dynamic.

To illustrate this, let’s make a small tweak to our code to read the title from the query string, instead of a hard-coded string. We will add a new method named get_title which will parse the env hash to fetch the query string, and return its value.

require 'erb'

class App
  def call(env)
    headers = { 'Content-Type' => 'text/html' }

    return [200, headers, ['favicon']] if env['PATH_INFO'] == '/favicon.ico'

    title = get_title(env) # new code here
    template = ERB.new template_html
    response_html = template.result binding

    [200, headers, [response_html]]
  end

  private

  def get_title(env)
    query = env['QUERY_STRING'] # "title=rak"
    values = query.split('=')   # ["title", "rack"]
    values[1]                   # rack
  end

  def template_html
    File.read 'views/index.html.erb'
  end
end

Now append ?title=whatever to the existing URL and refresh the browser. You should see the browser display whatever text you typed in the URL.

Dynamic Page Demo

Congratulations, you now have a fully dynamic web application. In the next article, we will add some tests for our application. That way, we don’t have to reload the browser after making a change, to ensure we didn’t brake our app.