Using Sinatra Helpers to Clean Up Your Code

Darren Jones
Darren Jones

Image courtesy of Shutterstock

A couple of months ago, I wrote an article about how I rapidly built my personal site using Sinatra. While I was building the site I started thinking about the best way to add JavaScript files to the pages. After playing with it for a while, I ended up using some custom helper methods to add JavaScript files to any page. It’s actually very easy to add javascript files to pages in Sinatra using the layout file. For example, if you want to include JQuery and a custom JavaScript file (called application.js) on all pages, then all you need to do is put the following lines of code in your layout file: [gist id=”2569440″] (This assumes that the Javascript files are in the public folder). Putting this code in the layout file means that they will be included on every page. However, some JavaScript files might only be needed on certain pages. For example, you might only want the file email.js
to be loaded on the contact page. It turns out that there’s a simple way to add things dynamically to layout files – instance variables. These can be set in the routes and then refererred to in the views. I use the instance variable @js to add a custom JavaScript file to a route: [gist id=”2569442″] I can then add an extra line to my layout file that will include the relevant script tag if the @js variable has been set. [gist id=”2569446″] This is a big improvement. It means that you can add a javascript file on a route-by-route basis. The only problem is that you can only add one file per route. To get round this, you can change the instance variable to an array of JavaScript files: [gist id=”2569451″] This also requires the line in the layout file to be changed so that it iterates through each string in the array and adds a script tag for each JavaScript file: [gist id=”2569461″] So far, so good – we are now able inject custom JavaScript files into the layout of individual routes. Since we’re looping through all of the custom JavaScript files in the @js array, why not just add scripts that will appear on all pages (application.js and JQuery) to the array as well? This can be achieved by creating another array, using Sinatra’s settings method, called settings.javascripts
. This array can be placed anywhere in your ruby file (I like to keep it near the top) and contains all the JavaScript files that are to be included on all the pages: [gist id=”2569466″] These two arrays need to be added together to create one big array to iterate over. The uniq method is used to avoid any repetition in case a file gets added to the @js array that has already been placed in the settings.javascripts array: [gist id=”2569481″] This amount of logic in a view looks messy, which is always a bad sign. The best way to deal with lots of view logic is to abstract it into a helper method. Helpers are easy to set up in Sinatra, you simply open up a block and place the methods inside. These methods are then available inside routes and views. Here’s a helper that can be used to clean up the layout: [gist id=”2569487″] Now all that’s needed in the layout file is this line: [gist id=”2569490″] Much cleaner. Since we’re now using a helper method, why not allow it to have arguments? This would allow us to add JavaScript files from within the layout file like before. This doesn’t take too much extra effort – adding an asterix before the name of the method’s parameter allows the method to take as many arguments as required. This means that we can add as many JavaScript files as we need for each route. Each argument forms part of the args array, which can now simply be added to the big array of JavaScript files that is iterated over in the layout (a bonus here is that we don’t have to check if it exists as it defaults to an empty array if no arguments are given): [gist id=”2569493″] Now we have three ways to add JavaScript files to a page:
  1. In the settings (this is for JavaScript files that are global to the whole site)
  2. In the layout file using the javascripts helper. This is used for JavaScript files that are common to all pages using this layout.
  3. In the handler using the @js instance variable. This is used to add JavaScript files on a route by route basis.
It may seem at first that methods 1 and 2 are virtually the same thing – a way to add global JavaScript files. But it is not uncommon to have different layouts for a site and it may be likely that each layout will require specific JavaScript files. The settings.javascripts
array should only be used for truly global JavaScript that are used throughout the site. The javascripts helper can be used to add JavaScript files on a layout by layout basis. We can improve on this further by using a helper method to set the @js instansce method. Rather than setting it directly in the handler, we can use a helper method called js that could be used to add any custom js files that are required for that route. This is also a good opportunity to clean up the javascripts helper method as it’s looking a bit brittle (it assumes that settings.javascripts
exists at the moment). [gist id=”2569499″] Our new js helper method means that things look a bit neater when called in the handler. This is especially true since the files are no longer required to be placed inside an array: [gist id=”2569501″] To finish off, let’s make it easier to add JQuery and other popular libraries when they’re required. This involves writing another helper method that uses shortcut symbols in place of the full url: [gist id=”2569503″] Now if you want to add a specific library all you need is the following code inside a route handler: [gist id=”2569505″] Notice that custom JavaScript files can now be entered as symbols and don’t need to have ‘.js’ appended to the end, as this is all done in the path_to helper method. With the helper method working how we want, it’s time to go modular and move it into a separate file. We first need to create a file called javascripts.rb and save it in a folder called ‘sinatra’ in the root directory of the app. All of the code inside the helpers block is then placed inside a module called JavaScripts. This module is then placed inside a module called Sinatra
(which is considered best practice when extending Sinatra with modules). The last thing to do is make sure to require Sinatra::Base at the top of the file. [gist id=”2569507″] The line helpers JavaScripts right at the end of the Sinatra module registers the helper methods so that they are available for use in the application. To use these helper methods, all you need is the following line of code in the main application file (main.rb): [gist id=”2569510″] We now have a convenient little helper that allows us to easily add JavaScript files exactly where they’re needed. A nice touch is that JavaScript files can also be added on a conditional basis in route handlers, like so: [gist id=”2569513″]

More Helper Methods

The method outlined above is not limited ot JavaScript files. A similar method could be used for adding CSS in a fine-grained way: [gist id=”2569515″] I’ve taken the whole concept further and built a module called HeadCleaner
that has a helper method for all the common items found inside the head of an html page such as meta, title, webfonts etc. This means that you can just use method calls to create a very minimal looking head section of the layout file such as the one shown below: [gist id=”2569519″] You can see the code here. It’s by no means perfect and I’d appreciate any feedback or help in developing this further (fork the code on github!). Ideas that I have for developing this are:
  • Allow users to set the path to javascripts
  • Have a separate yaml file with the shortcuts to external libraries in it so that it can be easily edited
  • Integrate with a JavaScript loader rather than having a separate script tag for each JavaScript file.
I hope these helpers are, well, helpful. If you’ve developed any helpers in your Sinatra development, do tell in the comments. Cheers! (Main Image courtesy of Shutterstock)

Frequently Asked Questions (FAQs) about Sinatra Helpers

What is the main purpose of using Sinatra Helpers in coding?

Sinatra Helpers are primarily used to clean up your code and make it more readable and maintainable. They allow you to encapsulate complex logic or repetitive tasks into separate methods, which can then be called within your application. This not only makes your code more organized but also promotes code reusability. For instance, if you have a piece of code that formats dates in a specific way and is used in multiple places, you can put this code into a helper method and call it whenever needed.

How do I create a helper method in Sinatra?

Creating a helper method in Sinatra is straightforward. You simply define a method within the helpers block in your Sinatra application. Here’s an example:

helpers do
def format_date(date)
date.strftime("%B %d, %Y")
In this example, format_date is a helper method that takes a date and returns it in a specific format.

Can I use Sinatra Helpers in any programming language?

Sinatra is a DSL (Domain Specific Language) for quickly creating web applications in Ruby. Therefore, Sinatra Helpers are specific to Ruby and cannot be used in other programming languages. However, the concept of helper methods is not unique to Ruby or Sinatra. Most programming languages have similar features, although they might be called differently.

How do I call a helper method in Sinatra?

Once you’ve defined a helper method, you can call it anywhere in your Sinatra application where methods are allowed. For instance, you can call it within your routes, views, or even within other helper methods. Here’s an example of calling a helper method within a route:

get '/date' do
In this example, when the ‘/date’ route is accessed, the format_date helper method is called with the current time as its argument.

Can I use Sinatra Helpers to interact with databases?

Yes, you can use Sinatra Helpers to interact with databases. In fact, it’s a common practice to encapsulate database queries or operations within helper methods. This not only makes your code cleaner but also allows you to reuse these operations wherever needed.

Can I use Sinatra Helpers in conjunction with other Ruby gems?

Absolutely. Sinatra Helpers are just methods, and they can interact with any Ruby code, including other gems. For instance, you might use a gem to handle user authentication, and then use a helper method to check if a user is logged in.

Can I define Sinatra Helpers in separate files?

Yes, you can define Sinatra Helpers in separate files to keep your code organized. You just need to require these files in your main Sinatra application file. This is particularly useful when you have a large number of helper methods.

Can I test Sinatra Helpers?

Yes, you can and should test your Sinatra Helpers. You can use any Ruby testing framework, such as RSpec or MiniTest, to write tests for your helper methods. This ensures that your helpers work as expected and makes your code more robust.

Can I use Sinatra Helpers to handle user input?

Yes, you can use Sinatra Helpers to handle user input. For instance, you might have a helper method that sanitizes user input to prevent SQL injection attacks. You can then call this helper method whenever you need to process user input.

Can I use Sinatra Helpers to generate HTML?

Yes, you can use Sinatra Helpers to generate HTML. In fact, this is a common use case for helper methods. For instance, you might have a helper method that generates a navigation bar or a footer. You can then call this helper method in your views to render the navigation bar or footer.