Open Graph Preview and Rails Meta Tag Generator
Paste a URL. We read its Open Graph, Twitter card and standard meta tags from our server, draw the card each platform builds out of them, and write the Slim or ERB block that would emit the set your layout is missing.
The Rails block that emits these tags
app/views/layouts/application.html.slim
meta property="og:title" content=@post.title
meta property="og:description" content=@post.summary
meta property="og:image" content=image_url("social-card.png")
meta property="og:url" content=post_url(@post)
meta property="og:type" content="article"
meta property="og:site_name" content="My Rails App"
meta name="twitter:card" content="summary_large_image"
meta name="twitter:title" content=@post.title
meta name="twitter:description" content=@post.summary
meta name="twitter:image" content=image_url("social-card.png")
meta name="twitter:site" content="@my_handle"app/views/layouts/application.html.erb
<meta property="og:title" content="<%= @post.title %>">
<meta property="og:description" content="<%= @post.summary %>">
<meta property="og:image" content="<%= image_url("social-card.png") %>">
<meta property="og:url" content="<%= post_url(@post) %>">
<meta property="og:type" content="article">
<meta property="og:site_name" content="My Rails App">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="<%= @post.title %>">
<meta name="twitter:description" content="<%= @post.summary %>">
<meta name="twitter:image" content="<%= image_url("social-card.png") %>">
<meta name="twitter:site" content="@my_handle">An example, until you read a URL above.
Put it in the layout head and feed the values from the page, not from literals - og:url wants the absolute URL of the canonical page, and og:image wants an absolute URL too, which is why the host belongs in default_url_options.
The page is fetched by our server. Only the preview image is loaded by your browser, straight from the site being checked.
Where the tags belong in a Rails layout
The og: set describes one page, so it belongs in the layout head with the values coming from that page. Rails renders the template before the layout, so a content_for set in a view reaches a yield in the head and the ordering works. What does not work is emitting the tags from the view body: a crawler takes the head and stops reading. Keep one block in app/views/layouts/application.html.slim, have it read helper methods that carry sensible defaults, and let each view override only the two or three values that actually differ.
og:image, image_url and default_url_options
og:image is the tag that works in development and breaks in production, and nearly always for one reason. A crawler fetches the image from its own machine, with no page to resolve a relative path against, so image_path is wrong here and image_url is right. image_url needs a host, and that host comes from Rails.application.routes.default_url_options - setting it only for Action Mailer is the usual miss. Active Storage follows the same rule: rails_blob_url, not rails_blob_path. Set the host in every environment file and the tag is absolute everywhere.
og:url is not link rel=canonical
They answer different questions and a page wants both. A canonical link tells a search engine which of several addresses to index. og:url tells a platform which address a share belongs to, and it is the key the share and like counts are kept against. Point them at the same URL and a share of the newsletter variant is counted with the clean one instead of beside it. In Rails that means one URL helper used twice - once for the canonical tag, once for og:url - and never request.original_url, which carries whatever query string the visitor arrived with.