Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Relative Assets with Directory Indexes #818

geoffreywiseman opened this issue Mar 13, 2013 · 19 comments · Fixed by middleman/

Relative Assets with Directory Indexes #818

geoffreywiseman opened this issue Mar 13, 2013 · 19 comments · Fixed by middleman/


Copy link

geoffreywiseman commented Mar 13, 2013

After doing a bunch of poking around Padrino, asset_url, etc, I have come to the possibly erroneous conclusion that although you can group assets with blog posts using directory indexes (activate :directory_indexes), you can't refer to the assets from the blog post without an absolute URL. I find that irritating, although obviously I can make it work.

If I'm wrong, let me know how I can do it so I can test it and maybe contribute a documentation patch. If I'm right, I'm not sure what approach you'd like to take -- maybe connecting asset_path to url_for or something else of that nature. In any case, if this isn't currently possible, then I'd like to request it.

Copy link

bhollis commented Mar 13, 2013

Hi @geoffreywiseman, would you mind telling us what stuff you've tried? For example, I would expect that url_for(<source path>) would give you the right URL.

Copy link

geoffreywiseman commented Mar 13, 2013

Sure. My initial test for this were on a blog page:


If I added markdown for the image on the page:

![Food Photo](plate.jpg "Ahi Tuna Meal")

The image would point to /images/plate.jpg instead of /source/blog/2013/02/23/picky-ahi-tuna/plate.jpg. After trying a few options, I eventually modified the blog entry to use the absolute path, posted on the forum. When that didn't net me an answers, I tried a few sessions of alternatives.


After trying the markdown approach, I thought I'd see if it was different using ERB, so I did:

<%= image_tag "plate.jpg" %>

This was still an absolute path to /images/plate.jpg.

image_tag, relative

After looking over the documentation some more, I tried an .html.erb again, this time with:

<%= image_tag "plate.jpg", :relative => true %>

No effect. After the next session, I could see this wasn't being checked.


Then I ran a debug session using Ruby 1.9 and the debugger gem, using an .html.erb (since I think of an easy way to invoke the debugger from within a markdown page) and traced through the code to see if I could see any way of doing relative links. Although that did show me that url_for existed, it showed me that image_tag didn't use it, and that markdown images go through image_tag.

I didn't then try building the image tag myself using url_for, although it's possible that as you're suggesting, it would work. That said, unless I can get that to work in markdown (and I don't see how, unless I do, then it doesn't change anything for me, I'll just end up doing markdown with absolute links.

Copy link

geoffreywiseman commented Mar 13, 2013

Hm. For reasons I haven't quite yet grokked, url_for seems unavailable to me:

== Request: /blog/2013/03/12/debug/index.html
       error  build/blog/2013/03/12/debug/index.html
undefined method `url_for' for #<Middleman::Application:0x70134897338440>
/Users/geoffrey/<path>/middleman/source/blog/2013-03-12-debug.html.erb:2:in `evaluate_source'
/Users/geoffrey/.rvm/gems/ruby-1.9.3-p392/gems/tilt-1.3.3/lib/tilt/template.rb:209:in `instance_eval'
/Users/geoffrey/.rvm/gems/ruby-1.9.3-p392/gems/tilt-1.3.3/lib/tilt/template.rb:209:in `evaluate_source'
/Users/geoffrey/.rvm/gems/ruby-1.9.3-p392/gems/tilt-1.3.3/lib/tilt/template.rb:144:in `cached_evaluate'
/Users/geoffrey/.rvm/gems/ruby-1.9.3-p392/gems/tilt-1.3.3/lib/tilt/template.rb:127:in `evaluate'/

I can see that it's defined on the 3.0-stable tag, so it must be something to do with how the helper methods are bound and available during the instance_eval, but I don't know that part of the middleman codebase well.

Copy link

bhollis commented Mar 15, 2013

Hm, are you sure you're using the latest Middleman release? url_for should be available.

The problem you're having is that url_for and its brethren like link_to and image_url operate on source paths. Given the two source paths:


You can see that plate.jpg can't be referred to as plate.jpg relative to 2013-02-23-picky-ahi-tuna.html. Instead, it must be 2013-02-23-picky-ahi-tuna/plate.jpg. Not ideal, but it works.

The problem with just using plate.jpg is that it looks for a Sitemap resource named plate.jpg relative to /source/blog/2013-02-23-picky-ahi-tuna.html and doesn't find it, so it falls back to image_url's default behavior, which is to assume the referenced image is in /images/ (that's a Padrino thing).

Does that at least make sense of the current behavior? We always use source paths for helpers and things, because extensions can modify the output paths willy-nilly. By always using source paths, you can do things like decide to start or stop using :directory_indexes and all your links will work properly either way. If we ever operated on the output paths, any extension that messed with those paths (like :directory_indexes) would cause your site to break.

Copy link

michaelbaudino commented Mar 15, 2013

It makes perfect sense.

Using Markdown, though, I have no idea how to use relative paths for images.
I managed to do something like this:

![Some picture](/posts/2013-03-15-some-interesting-post/some-image.png "Some picture")

Again, not ideal, but it works.

Copy link

geoffreywiseman commented Mar 15, 2013

Ah, yes, I was using Middleman 3.0.11 and middleman-blog 3.1.1; updated and url_for works. That presumably doesn't help me with markdown, though. It doesn't look like middleman-blog will let me do /blog/2013-03-12-debug/ either:

$ middleman build
/Users/geoffrey/.rvm/gems/ruby-1.9.3-p392/gems/middleman-blog-3.2.0/lib/middleman-blog/blog_data.rb:121:in `block in manipulate_resource_list': Article for blog/2013-03-12-debug/index.html not found (RuntimeError)
    from /Users/geoffrey/.rvm/gems/ruby-1.9.3-p392/gems/middleman-blog-3.2.0/lib/middleman-blog/blog_data.rb:92:in `each'
    from /Users/geoffrey/.rvm/gems/ruby-1.9.3-p392/gems/middleman-blog-3.2.0/lib/middleman-blog/blog_data.rb:92:in `manipulate_resource_list'
    from /Users/geoffrey/.rvm/gems/ruby-1.9.3-p392/gems/middleman-core-3.0.12/lib/middleman-core/sitemap/store.rb:222:in `block (2 levels) in ensure_resource_list_updated!'

So, if you're using markdown and middleman-blog with article subdirectories, I guess we just have to use absolute URLs?

Source Paths

I see what you're saying about source paths, which is why it occurred to me to try turning the blog article into an version instead. However, you say that url_for needs to use source paths, and yet, I can use "plate.jpg" in url_for and it seems to work?

Copy link

michaelbaudino commented Mar 17, 2013

Sorry, actually, my solution does not work, and I may have found a bug.

As mentionned above, I'm trying to include an image which lies in an article subdirectory:

![Some picture](/posts/2013-03-15-some-interesting-post/some-image.png)

The problem is that the following HTML code is generated:

<img alt="Some picture" width="1039" height="577" src="/posts/some-interesting-post">

Note that the src attribute should rather be /posts/some-interesting-post/some-image.png, isn't it ?

When building with bundle exec 'middleman build --clean --verbose', the image is built as /build/some-interesting-post (without extension), which is coherent with the generated HTML, but if I have another image (or any other asset, btw) in the subdirectory, it raises the following error:

== Request: /posts/some-interesting-post/index.html
== Finishing Request: posts/some-interesting-post/index.html (0.03s)
      create  build/posts/some-interesting-post/index.html
       error  build/posts/some-interesting-post/index.html
File exists - /home/mike/AlpineLab/code/blog-alpinelab/build/posts/some-interesting-post
/home/mike/.rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/fileutils.rb:247:in `mkdir'
/home/mike/.rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/fileutils.rb:247:in `fu_mkdir'
/home/mike/.rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/fileutils.rb:221:in `block (2 levels) in mkdir_p'
/home/mike/.rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/fileutils.rb:219:in `reverse_each'
/home/mike/.rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/fileutils.rb:219:in `block in mkdir_p'
/home/mike/.rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/fileutils.rb:205:in `each'
/home/mike/.rvm/rubies/ruby-1.9.3-p392/lib/ruby/1.9.1/fileutils.rb:205:in `mkdir_p'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/thor-0.15.4/lib/thor/actions/create_file.rb:62:in `block in invoke!'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/thor-0.15.4/lib/thor/actions/empty_directory.rb:133:in `call'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/thor-0.15.4/lib/thor/actions/empty_directory.rb:133:in `invoke_with_conflict_check'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/thor-0.15.4/lib/thor/actions/create_file.rb:61:in `invoke!'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/thor-0.15.4/lib/thor/actions.rb:95:in `action'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/thor-0.15.4/lib/thor/actions/create_file.rb:26:in `create_file'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/middleman-core-3.0.12/lib/middleman-core/cli/build.rb:140:in `render_to_file'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/middleman-core-3.0.12/lib/middleman-core/cli/build.rb:275:in `block in execute!'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/middleman-core-3.0.12/lib/middleman-core/cli/build.rb:272:in `each'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/middleman-core-3.0.12/lib/middleman-core/cli/build.rb:272:in `execute!'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/middleman-core-3.0.12/lib/middleman-core/cli/build.rb:191:in `invoke!'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/thor-0.15.4/lib/thor/actions.rb:95:in `action'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/middleman-core-3.0.12/lib/middleman-core/cli/build.rb:65:in `build'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/thor-0.15.4/lib/thor/task.rb:27:in `run'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/thor-0.15.4/lib/thor/invocation.rb:120:in `invoke_task'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/thor-0.15.4/lib/thor.rb:275:in `dispatch'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/thor-0.15.4/lib/thor/base.rb:425:in `start'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/middleman-core-3.0.12/lib/middleman-core/cli.rb:77:in `method_missing'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/thor-0.15.4/lib/thor/task.rb:29:in `run'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/thor-0.15.4/lib/thor/task.rb:126:in `run'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/thor-0.15.4/lib/thor/invocation.rb:120:in `invoke_task'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/thor-0.15.4/lib/thor.rb:275:in `dispatch'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/thor-0.15.4/lib/thor/base.rb:425:in `start'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/middleman-core-3.0.12/lib/middleman-core/cli.rb:22:in `start'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/gems/middleman-core-3.0.12/bin/middleman:18:in `<top (required)>'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/bin/middleman:19:in `load'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/bin/middleman:19:in `<main>'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/bin/ruby_noexec_wrapper:14:in `eval'
/home/mike/.rvm/gems/ruby-1.9.3-p392@blog-alpinelab/bin/ruby_noexec_wrapper:14:in `<main>'

This error seems pretty logic, as it tries to build all assets in an article subdirectory to the same filename.

If it helps, here is my config.rb:

# Automatic image dimensions on image_tag helper
activate :automatic_image_sizes

activate :blog do |blog|
  blog.prefix = 'posts'
  blog.permalink = ':title'
  blog.default_extension = '.md'
  blog.layout = 'post'
  blog.paginate = true

# Directory Indexes
activate :directory_indexes = 'Paris'

# Methods defined in the helpers block are available in templates
# helpers do
#   def some_helper
#     "Helping"
#   end
# end

set :css_dir, 'css'

set :js_dir, 'js'

set :images_dir, 'img'

set :markdown_engine, :redcarpet
set :markdown,
  fenced_code_blocks: true,
  autolink: true,
  smartypants: true,
  gh_blockcode: true,
  lax_spacing: true

activate :rouge_syntax

# Build-specific configuration
configure :build do
  # For example, change the Compass output style for deployment
  activate :minify_css

  # Minify Javascript on build
  activate :minify_javascript

  # Minify HTML
  activate :minify_html

  # Enable cache buster
  # activate :cache_buster

  # Use relative URLs
  activate :relative_assets

  # Add asset fingerprinting to avoid cache issues
  activate :asset_hash

  # Compress PNGs after build
  # First: gem install middleman-smusher
  # require "middleman-smusher"
  # activate :smusher

  # Or use a different image path
  # set :http_path, "/Content/images/"

activate :deploy do |deploy|
  deploy.method = :git
  deploy.remote = 'gh-pages'
  deploy.branch = 'master'

activate :livereload

I tried to activate Smusher (you never know), but it did not help.
I also ran a bundle update before testing this, so my gems are all up-to-date.

Any idea ? Smells like a bug, doesn't it ?
Or did I miss something ?

Copy link

geoffreywiseman commented Mar 18, 2013

I don't have that problem, although I don't have the identical configuration to you -- I might try adding a few things that you have in your file to see if I can reproduce (e.g. automatic image sizes).

Copy link

xlab commented Jul 17, 2013

Hi there! I have the same issue here (#issuecomment-14838455 for sure).

I need to produce something like

<dl class="explained">
  <dt><img src="image.jpg"/></dt>
  <dd>This is a cool picture</dd>

So I use helper like that:

helpers do
  def explained_img img, explanation
<dl class="explained">

But it's necessary to call it with full paths, I'm calling it from a markdown source of a blog post:

<%= explained_img '/posts/2013-07-16-forest/squirrel.jpeg', 'Fig. 1: Running squirrels' %>

My humble solution

Use caller[0] magic. That will return something like this:

/Users/xlab/Documents/Coding/Web/ block in singleton class

The simplest way to get the desired string is

'/posts/' + caller[0].split(':').shift().split('/').pop().split('.').shift()
 #=> "/posts/2013-07-16-forest"

So my helper is

def explained_img img, explanation
prefix = '/posts/' + caller[0].split(':').shift().split('/').pop().split('.').shift() + '/'
<dl class="explained">
  <dt>#{image_tag(prefix + img)}</dt>

One could think about regexp, paths parsers, path builders, some verifications and etc. Good luck.

Copy link

airblade commented Aug 2, 2013

I have this problem too. My workaround is to run my markdown through ERB first:

In /notes/some-article.html.markdown.erb:

![Some text](<%= current_page.url %>my-image.png)

It's not ideal but it's better than a poke with a stick.

Copy link

tdreyno commented Aug 2, 2013

Pretty sure caller[0].split(':').shift().split('/').pop().split('.').shift() is a sequence from Dance Dance Revolution :)

In all seriousness, I'll look into writing tests to provide us with a target to fix.

Copy link

bhollis commented Sep 22, 2013

This is really not easy to fix. I came up with a patch to url_for that looked like it would fix it, but once you throw in something that messes with resourcesdestination_path (like:asset_hash`) you're back in trouble, because you'd need to link to the asset-hashed version of your image rather than its normal filename.

At this point I think we should just document that you should link to images by repeating the blog post name (like ![myimage](2013-09-22-my-blog-post/my-image.png) or use a workaround like @airblade's.

Copy link

michaelbaudino commented Sep 23, 2013

Yeah, I end up repeating the blog post name each time. Do you need a PR with an updated doc ?

Copy link

bhollis commented Sep 23, 2013

That'd be great.


Sent from my phone

On Sep 23, 2013, at 10:06 AM, Michael Baudino

Yeah, I end up repeating the blog post name each time. Do you need a PR
with an updated doc ?

Reply to this email directly or view it on

Copy link

mcoms commented Aug 19, 2014

The middleman homepage still warns users to use the article subdirectory (Blogging > Article Subdirectory) in relative links, but #1048 seems to fix it — is the warning still required?

/ed: Ah, yes — image_tag for example still needs the directory name in there.

Copy link

erikdahlstrand commented Aug 22, 2014

After moving the image to the article subdirectory I get an extra (empty) alt attribute in the img element.

![Some picture](/posts/2013-03-15-some-interesting-post/some-image.png)
<img alt="Some picture" alt="" width="1039" height="577" src="/posts/some-interesting-post">

Anyone else having this problem?

Make sure you are looking in the raw page response because the empty alt attribute is removed in the element browser of both Safari and Chrome.

Copy link

lolmaus commented Aug 22, 2014

@erikdahlstrand Looks like a bug. Please file a separate issue. Ideally, include a link to a Github repo with a minimal Middleman project that demonstrates the issue.

Copy link

tdreyno commented Aug 22, 2014

@erikdahlstrand Are you using automatic_image_sizes?

Copy link

erikdahlstrand commented Aug 22, 2014

@tdreyno Yes I do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment