This Gem is Mentionable

Caleb Hearth - Feb 9 '23 - - Dev Community

Mentionable is a gem that provides support for inbound Webmentions and microformats in Rails apps.

Mentionable is useful for blogs, news sites, apps that have associated blogs, social apps, and any other Rails app that might be linked to or that links out to other websites.

I mentioned (heh) that I’d been working on a gem to handle inbound Webmentions in Rails on my first newsletter issue last month, but I haven’t spoken too loudly about it elsewhere. While I’ve had it running here on my site since November of 2022, it hasn’t been ready to actually use because it’s really only been saving incoming Webmentions but hasn’t provided a very good API for using them. Until this week that is.

Wait back up what is a Webmention?

Webmentions are a way for sites to share that they’ve linked to one another. At a very high level, when a site that wants to send Webmentions publishes new content, it can loop through every URL that’s linked to (or embedded, as for a <video>, <audio>, etc.) and check to see if the target of that link supports Webmention by querying for a <link rel="webmention"> element or an HTTP Link header with rel="webmention". If it does, it sends a POST to that URL with the target URL (the page that’s been linked to) and source URL (the page that’s doing the linking). That’s it! You’ve sent a Webmention.

Receiving a Webmention involves checking that the target is actually one of your URLs, saving the Webmention, and later confirming that the source links to the target. Up to now, this is what Mentionable has handled for me. Since setting it up, I’ve received about 100 Webmentions and they’ve been sitting in the site’s database. I’ve been using Brid.gy which polls sites like Mastodon, Reddit, GitHub, and other “siloes” for links to my site, builds a page that’s representative of that link, and sends a Webmention to that representation with a <meta http-equiv="refresh” content> tag that points to the original. Lobste.rs—the smaller, friendlier Hacker News—also sends Webmentions when a link is shared there.

To actually make use of a Webmention, you could settle for linking to each source on the relevant pages, but it’s more useful to parse the HTML of the page and somehow figure out how to render the content meaningfully. It’s possible to build heuristics to figure this out, but even better is to use microformats.

Microformats Items

Microformats are relatively simple sets of classes that allow websites to mark up structured data such as blog posts, people, recipes, books, citations, etc.

The microformats that are most important to Mentionable are h-card and h-entry, which are used to denote people/organizations and blog posts/comments, respectively. Mentionable also parses h-adr and h-cite which are microformats that tend to be useful within h-card or h-entry and especially for marking up comments in the case of h-cite. Collectively, these are called microformats (or more precisely microformats2) or sometimes as “h-*”.

There is a Ruby gem that implements microformats parsing, among other things. While it is able to correctly parse out the expected microformat items JSON, that isn’t the easiest format to work with in Ruby, where objects provide an easier interface.

What’s changed in Mentionable this week?

Mentionable now provides an object-oriented wrapper around the h-entry and h-card specs and can return a collection of microformat items from the HTML of the source that is incidentally fetched as part of verifying the Webmention and is cached in the database by default. Mentionable::Mention#microformat_items returns an array of h-* wrapper classes that make reasonable assumptions of the shape of microformat items and presents them as data objects. This makes it much simpler to render Webmentions on a page:

<section class="mentions h-feed">
  <% h_entries.each do |mention| %>
    <article class="mention p-comment h-cite">
      <header>
        <%= link_to mention.author.urls.first, class: "p-author h-card" do %>
          <%= mention.author.name %>
        <% end %>
        <%= link_to mention.url, class: "dt-published" do %>
          <%= time_tag mention.published %>
        <% end %>
      </header>
      <section class="p-content">
        <%= sanitize(mention.content.map {|c| c["html"] }.join("\n").html_safe) %>
      </section>
    </article>
  <% end %>
</section>

Enter fullscreen mode Exit fullscreen mode

What needs to happen?

A lot! While I do think that Mentionable is at a point that early adopters might find it useful, there are major improvements that can still be made.

  • Unfurling and conversation trees. Mastodon Webmentions that come in via Brid.gy have in_reply_to links that are redirects from your home instance to the instance of the post author. Unfurling these would allow us to build a “conversation tree” where each post points to all of its responses where in_reply_to references the post’s URL property.
  • Categorization. H::Entity can represent a reply, share, bookmark, like, etc. depending on what properties are present. Helper methods, scopes, and/or a “type” enum would make it easier to split these up when rendering Webmentions.
  • Sending Webmentions! I intend for Mentionable to handle outbound Webmentions as well. It’ll take an arbitrary object, search for external URLs, and enqueue jobs to check for Webmention endpoints and send Webmentions.
  • Documentation. Mentionable is particularly documented, but the new H module and it’s children are completely undocumented and its README is out of date.

Try it out!

Mentionable is definitely beta software at this point, but as it is currently inbound only, the risk is pretty low. Even if you only set up a Webmention endpoint and begin verifying and saving inbound Webmentions, you’ll be well on your way to joining the Indieweb. The more sites supporting Webmention and microformats the more momentum we’ll see for sites like Mastodon, Wordpress, and maybe even news sites and company blogs to send these out. In fact, if your company’s blog is on Rails, I’d love to see them add Mentionable as well.

Even better, try out embedding your Webmentions on each page using Mentionable::Mention#microformat_items once they start to come in. I’m sure there are improvements that can be made to the interface, so please reach out on GitHub if you have suggestions. Issues, comments, and Pull Requests would be very welcome.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .