How we used Nokogiri to fix a sizing issue in YouTube's oEmbed

At some point, one of our calls to YouTube's oEmbed endpoint was returning videos way too small; we fixed in in our Rails application by using Nokogiri

On PinTraderClub, we allow people to add certain types of media to their articles. To do this, we use oEmbed implementations supplied by Twitter, Facebook, YouTube, etc.

With oEmbed, you make a call to an endpoint supported by the target service. With YouTube, for example, we make a call to https://www.youtube.com/oembed?url=#{url}&format=json, and it will return a JSON object that describes the content.

One bit of information returned is the HTML you need to display the object. When we first implemented everything, the HTML returned used a suitable size for our use case, so we thought nothing of it and shipped the feature.

At some point, YouTube changed the default size of their video to the smallest version they support, which is way too small for our needs.

A tiny YouTube preview, with buttons beside it for context as to how small it is
This is the size of video being returned, way too small to be useful

With oEmbed, you can specify the max size you want back, but not a minimum size. Unfortunately, this means the solution isn’t as easy as asking for a larger video to be returned.

Enter Nokogiri

Nokogiri is a Ruby tool for working with XML and HTML.

In our code we were doing something like;

self.html = json.html

This would take the HTML given to us by the JSON object and assign it to our model that stores all the embed information.

Using Nokogiri to manipulate the HTML took fewer lines of code than I expected;

doc = Nokogiri::HTML::DocumentFragment.parse(json.html)
iframe = doc.at_css 'iframe'
iframe['height'] = '360'
iframe['width'] = '640'
self.html = doc.to_html

First, we create a doc which appears to be a common variable name used when dealing with document objects created by Nokogiri.

Nokogiri::HTML::DocumentFragmant is the class we want in this case because it is HTML, and it isn’t a complete HTML page, just a selection of HTML.

The parse method accepts a string and converts it into a Nokogiri document object.

YouTube does everything within an iframe. By calling doc.at_css 'iframe' we use a CSS selector of “iframe” to get the element we care about.

The following two lines manipulate the attributes held against that object, namely width and height.

Finally, we need to turn our Nokogiri document object back into HTML; we do that with doc.to_html.

A simplified version of our HTML might have started like this;

<iframe width='50' height='50' src='blah'>

After passing through Nokogiri, it will look identical bar the attribute changes we made;

<iframe width='640' height='360' src='blah'>

This method is not without issue. If YouTube changes how they deliver videos, then this code could break, and we’d need to revisit it. For our use case, we decided this is an acceptable trade-off.


Recent posts View all

Ruby

Testing Routes with RSpec

Testing routes can give you more confidence and help drive application development; here is how to do it with RSpec

Ruby

How to ignore Bullet in RSpec tests

Using Bullet during a test can pick up mistakes but also has false negatives; here is an easy way to ignore them