Rails Image Helper
Often times when developing application, there are times that a developer may need to include logic to conditionally render UI elements. For instance, maybe an active CSS class in 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
On 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 images 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 available images are not currently available for the new members. When the image is not available, the browser developer console logs a 404 status code, and the UI displays a broken image, thereby breaking 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 this image.
- Check for unsuccessful access of an image 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 in app/helpers
called bio_image_helper.rb
. The basic structure of the helper is to create a module and then within the module, a method we will call within our view. We are going to define the URI string in a variable and pass 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 success of the image response, and offer a fallback image. We will use two libraries to meet these objectives: net/http
and uri
. With these, we will store to 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 which helped the most.
Footer
This has been fun. Leave a comment or send me a DM on Twitter.
Shameless Plug: If you work at a great company and you are in the market for a Software Developer with a varied skill set and life experiences, send me a message on Twitter and check out my LinkedIn.