Images in Blog Posts

Hey guys,

Im trying to display images in a blog post, and Im struggling with the syntax (i.e. I have figured out how to do it but it seems very verbose) and Im wondering if anyone has a better / cleaner solution to include images in posts.

I have Directory Indexes enabled, and I place my images in a subdirectory with the same name as the post (as described in the middleman documentation).

The only way I can successfully display this image is:

<img src="./ArticleName/ImageName.png" alt="">

or in Markdown:

![](./ArticleName/ImageName.png)

Now this seems relatively short, but my article titles end up being pretty long making the actual result look like this

<img src="./PYXL_Behind_the_Scenes-_From_Sketchbook_to_iOS_app/photo-1.jpg" alt="">

Ideally I would love to just use a rails helper and have it recognize relative assets properly and just be able to do

<%= image_tag (photo-1.jog) %>

or even just directly refer to the image via the html tag (without having to include the relative path to the image.

Has anyone figured out how to do this? Is there any helper function out there I could use to implement this?

Thanks guys!

Bump? Anyone have any thoughts on this?

Hi @salmansqadeer,

Here’s one solution. Inside config.rb:

helpers do

  def article_dir
    pieces = current_page.url.chomp("/").split("/")
    pieces[-1] = File.basename(pieces.last, File.extname(pieces.last))
    pieces.join("/")
  end

  def article_asset_path(path)
    File.join(article_dir, path)
  end
  
  def article_image_tag(path, *args)
    args.unshift article_asset_path(path)
    image_tag(*args)
  end

end 

Inside your blog post:

<%= article_image_tag("cat.jpg") %>

The downside to using a helper like this is that current_page is not what you expect when using the article in a collection page (such as index.haml) that does something like:

- blog.articles[0...10].each do |article|
  %li = article.body

The issue is that current_page is the index.haml page, and not the article’s page.

I just ran into this issue, because I was using a solution like the one above (i.e. using current_page to build a path in a helper), and now want to include the article body in a collection page, and my helpers break.

I notice that in the collection page, where I have the article object, it is of class Middleman::Sitemap::Resource, which has all the info I want. But, I don’t know how to get that same info from inside the content of the article itself. Is that possible?

1 Like

Maybe using @Aupajo’s helper process but trying to get something from article.title or article.slug instead of current_page.url would work, since blog.permalink and blog.sources are related with the article title, and there is where your asset folder is going to be.

Unless I’m missing something, I can’t see how I can get at the article object from inside the helper method.

Even if I wanted to pass in the article to the helper method, I can’t see how to get it from within the article’s content file (e.g. my-post.md.erb). (And, it would be nice not to have to pass anything in like that.)

The only place that actually has the article object is when iterating over blog.articles.each on the collection page. But, I don’t see any way to “pass in an argument” when rendering article.body. And, furthermore, that code path isn’t used when rendering the article page normally, so it wouldn’t solve that case. Again, I’d be happy to hear if I’m missing something.

I’m not sure if this is possible, or the right approach, but It seems like it would be nice if blog.articles.each would set some local state so that current_article was valid when rendering the content of the article. Then I could just use that from my article content or any helper method.

Sorry, I’m the one missing something! You’re right, I tried to replicate this as soon as I got back home and now I see all the issues you are having. My bad.

So, do you have any suggestions about how to solve or work-around it?

Sorry for the delay Kelan, I didn’t find any solution yet. I’m starting to think that using both “custom blog images helper” and blog.body at the same time is not even possible.

I have an idea for a workaround.

Instead of trying to get the article object from inside the helper method, set it before article.body is fetched.

Like this:

- blog.articles[0...10].each do |article|
  $current_blog_post = article.destination_path
  %li = article.body

Then call the helper method from inside my-post.md.erb with

<%= article_image_tag("cat.jpg") %>

Inside the the helper method you can now use the value of $current_blog_post.

I’ve tested it, and it seams to do the trick. However, some work remains before this is a functional solution. For example. using a global variable is far from ideal. But, hopefully, this will give you a starting point.

Instead of article.body you can use article.render({layout: false}).

article.render takes three arguments, named opts, locs, blocks – options, locals and blocks (of code). I’m quite sure you can use one of these to set a variable that an helper method can use (it should appear as frontmatter/metadata to the helper function). But I have yet to figure out the precise mechanics of this.

Solved.

With directory indexes on, and the image in a dir beside the article:

On the collection page, index.html.erb replace

article_body
with
<%= article_body_directory_indexes_safe(article) %>

Add these two functions to your config.rb

def article_body_directory_indexes_safe(article)
  article.render({layout: false}, {article: article})
end
def img(relative_path, alt='')
  article = current_resource.app.instance_variable_get("@current_locs")[:article]
  if article.nil?
    # On page
    url = current_page.url
  else
    # In listing
    url = article.url
  end

  "<img #{alt} src='#{url}/#{relative_path}'>"  # return
end

And finally, in your article, use this to insert an image:

<%= img('ImageName.jpg') %>

Note that the img helper function breaks encapsulation, so this may stop working with future versions of Middleman. Only tested with 3.3.7.

Alternative solution (probably more robust)

With directory indexes on, and the image in a dir beside the article:

On the collection page, index.html.erb replace

  <%= article.body %>

with

  <% $current_listed_article = article %>
  <%= article.body %>
  <% $current_listed_article = nil %>

Add this function to your config.rb

def img(relative_path, alt=nil)
  if $current_listed_article.nil?
    # On page
    url = current_page.url
  else
    # In listing
    url = $current_listed_article.url
  end
  alt ? alt_attr = "alt='#{alt}' " : alt_attr = ''

  "<img #{alt_attr} src='#{url}/#{relative_path}'>"  # return
end

And finally, in your article, use this to insert an image:

<%= img('ImageName.jpg') %>

This solution uses a global. Never an ideal solution. But in practice, I think it is quite robust, and more likely to survive the transition to Middleman 4 then the previous solution. Only tested with 3.3.7.

1 Like

@tommysundstrom- I apologize for the late response, but I used your “Alternative solution” and it’s working well for me on Middleman 3.3.7. It’s definitely not the most elegant solution, but it gets the job done. So, thank you!