Rails Image Helper

Often, when developing an application, a developer may need to include conditional logic to render UI elements—for instance, an active CSS class on the navbar menu item for the current page. Sometimes the required logic is more complex. In my case, I needed to provide a fallback image when an image was not available from the API. In this article, I will show the methodology I used to create a Rails Helper to meet this goal.

Structure

For my side project, Your Congress, I am using a free GitHub repository, UnitedStates/Images which stores all the photographs of serving Congress members. The images are accessible through an API served from GitHub pages, by image size and member ID. So, the image URL will be configured like so: https://theunitedstates.io/images/congress/[size]/[member_id].webp.

The image is rendered in the ERB partial:

image_tag "https://theunitedstates.io/images/congress/225x275/#{senator.member_id}.webp"

Problem

The existing code works fine, but as new members have been added to the US Congress, the images for the new members are not yet available. When the image is unavailable, the browser developer console logs a 404 status code, and the UI displays a broken image, thereby disrupting the card layout. So, there needs to be a better way to access these images and check for availability.

The goals:

  • Check for a success code when accessing the image, and render it if present.
  • Check for an image access failure and render a fallback image to preserve the UI layout.

This is too much complexity for the ERB partial, so to DRY out this process, we will create a Rails Helper.

Solution

What are helpers in Rails? A helper is a method that is (mostly) used in your Rails views to share reusable code. RubyGuides

We are creating a new helper app/helpers called bio_image_helper.rb. The basic structure of the helper is to create a module, then, within that module, a method that we will call in our view. We are going to define the URI string in a variable and pass it in the member_id in an argument called member. So the basic structure:

module BioImageHelper

def bioimage_helper(member)
img_url = "https://theunitedstates.io/images/congress/225x275/#{member}.webp"
res = Net::HTTP.get_response(URI.parse(img_url.to_s))

res.is_a?(Net::HTTPSuccess) ? img_url : 'backup.webp'
end

end

Remember, the second goal was to validate the image response's success and provide a fallback image. We will use two libraries to meet these objectives: net/http and uri. With these, we will store in a variable (res) the response object and parse the img_url string. Then use a Ruby ternary to check the response object for an HTTPSuccess, and use the image, or our fallback image.

require 'net/http'
require 'uri'

module BioImageHelper

def bioimage_helper(member)
img_url = "https://theunitedstates.io/images/congress/225x275/#{member}.webp"
res = Net::HTTP.get_response(URI.parse(img_url.to_s))

res.is_a?(Net::HTTPSuccess) ? img_url : 'backup.webp'
end

end

So, the image_tag in the partial, now is abstracted to:

image_tag bioimage_helper(senator.member_id)

Thanks

Special thanks to the users on the Ruby on Rails Discord Server who pointed me in the right direction, with feedback, and code review.

Also, the Stack Overflow discussion was most helpful.