Skip to content
This repository

image_tag("") tries to get an image from the asset_pipeline #3080

Closed
rafamvc opened this Issue September 19, 2011 · 39 comments
Rafael Cardoso

When image_tag receives a blank string, it tries to get a resource from the asset pipeline and returns

"isn't precompiled"

IMHO it should return a blank <img src=""/> or something like it.

Damien Mathieu
Collaborator

http://dev.w3.org/html5/markup/img.html

src = non-empty URL potentially surrounded by spaces

The HTML5 documentation is pretty clear about it. The src tag shouldn't be empty.
Why would you want to provide an empty string to your image_tag ? I believe you should manage, inside your application, what you want to display as a default image when the one you're trying to display is not available.

Rafael Cardoso

I did enforce my application already.
If you want to enforce HTML to be compliant your should output a error for the right thing. The asset pipeline should not search for it.

The behavior of a link_to "", "" will render a invalid HTML a as well.

My point is that the error is non descriptive, and rails can do a better job at it, for the next person that stumble on this. :)

Adrian Macneil

+1. In general this exception is pretty annoying. On a production site it's not very helpful that if image_tag receives an unexpected string the whole page fails to load.

Jochen Kramer

hey,

though html5 requires non-empty src attributes, rails should not throw an "isn't precompiled". its hard to find the root cause (its pointing to the asset pipeline instead of your code) and the former image_tag helper did behave different.

+1 for an empty src instead of throwing none-specific exceptions

Sergey Nartimov

:+1: it should not throw error

Godisemo

This seems to cause errors for me to. Should not raise exceptions IMHO.

Mathias Stjernstrom

+1 should not throw error

Mathias Stjernstrom

Maybe this could work, showing a blank image if string is empty.

module ApplicationHelper

  def image_tag(source, options={})
    source = "blank_image.gif" if source.blank?
    super(source, options)
  end

end

Or, if you do not want the image tag at all

module ApplicationHelper

  def image_tag(source, options={})
    super(source, options) if source.present?
  end

end
mipearson

+1. This just caused us a site outage as a staffer screwed up an image upload for a content item. We've worked around it in our code base, but we really shouldn't have to.

mipearson

Added a note to the asset pipeline guide: rails/docrails@85f71c5

Adrian Macneil

Would be easier if we could just get the bug fixed..

mipearson

Okay, I'm becoming less sure that this should be 'fixed', as it means that image_path becomes inconsistent with asset_path. I'm changing my +1 to a 0.

Other, custom, asset types might also not merit an Exception when missing (eg, fonts?). I believe an alternative solution should be discussed - maybe a config option to specify certain asset types as non-essential? A different helper method for data-driven content? Eh, I don't know.

Kirill Lashuk
KL-7 commented May 02, 2012

@mipearson, the problem is that current implementation is inconsistent across different environments. As I described in my PR you get image tag with meaningless src="/assets" in development mode and in production with assets precompilation turned on you get an exception out of the blue.

mipearson

@KL-7 I think having a blank asset_path call raising an exception would be a good solution to the above.

Adrian Macneil

Forget about the asset path for a second. image_tag is primarily an html helper function (e.g. if you are displaying images uploaded using carrierwave or whatever you already know the image url, the asset path isn't involved).

For example.. link_to("example", nil) works fine, it just links to '/'. Whatever, it doesn't really make sense, but the point is it doesn't raise an exception. This is how image_tag() behaved prior to Rails 3.1. Now, since 3.1, the existing behaviour broke (I'm sure this wasn't intentional). The asset path is the cause of the issue, but it doesn't excuse this behaviour.

The same is true of tag("img", :src => nil). Maybe it doesn't generate valid html, but it doesn't raise an exception. Now explain to me why image_tag() behaves differently to tag("img")?

When you call asset_path(), you know you are dealing with the asset path, so an exception is fine. When you call image_tag(), a lot of the time you aren't using the asset path at all (e.g. uploaded images), so I don't see why these two need to be consistent.

Carlos Antonio da Silva

Closing this since #5020 was merged. Thanks!

Carlos Antonio da Silva carlosantoniodasilva closed this May 18, 2012
Loïc Faure-Lacroix

Got that problem today. In my case, image_tag really has to be empty. We're using javascript to fill the blanks. In other words, when the template is rendered with erb. There is no content or almost none. And some part of the pages are actual templates for KnockOutjs. I could probably put a falsy url but it's not as simple.

Steve Klabnik
Collaborator
Loïc Faure-Lacroix

@steveklabnik what's the point of writing a helper someone offer to write <img /> instead of that helper. I fail to understand the logic. image_tag is a bit more than replacing the img tag. It has some parameters like size and mousehover etc...

And yes, I replaced the helper by the img tags everywhere I could. I think it's just quite funny to get offered to not use a helper because the helper isn't really helping. What kind of helper is that? =)

http://api.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html#method-i-image_tag

Carlos Antonio da Silva

I believe this has been fixed in the linked pull request. @llacroix which version are you seeing this? It might be that it wasn't backported to 3-2.

Steve Klabnik
Collaborator

@llacroix because <img /> is not valid HTML. If you want to write invalid HTML, do it by hand.

<img src="" /> is not valid either. At minimum, it must be <img src="#" alt=""/>.

Loïc Faure-Lacroix

@steveklabnik sure it's not valid html, but the html gets processed by javascript to fill up content.

I'm on rails 3.2 as a matter of fact. To sum it up:

image_tag('')
image_tag(nil)
Dev => <img src="/assets/" alt="" />
Production => Precompile error
image_tag(nil, alt: nil)
Dev => <img src="/assets/" />
Production => Precompile error

Uhoh invalid markup in dev without error

image_tag('#')
Dev => <img src="/assets/#' alt='#' />
Production => Precompile error
image_tag('http:///', alt: nil)
Dev: <img src="http:///" />
Production: <img src="http:///" />

Uhoh no need to precompile since it's pointing to http:/// and alt tag is missing... invalid markup works in production. Actually the markup created contains an invalid url and no alt tag.

That's two error in here: http://validator.w3.org/check

But to be honest, my big problem here is that the behavior in production and in development is different. It's not cool that it works very well in dev but once you run the server in production you have lots of "production" errors that only happen in production.

So yes, it's possible to do invalid markup using the image_tag, so I'd be rather happy if the helper only quoted correctly whatever I pass, generated valid html markup but invalid img markup, than trying to validate and img and failing at it a restraining me to process that generated html elsewhere.

I'd be quite happy with something like image_tag(strict: false). But that would probably complicate things since you can't then create a "strict" attribute on the html tag. Having a way to suppress validation and precompilation would be cool and saves lot of time and headache.

jack dempsey

Just chiming in with a "image_tag and blank string throws and error!?" (on rails 3.2.9). This really surprised me, and the error of "ActionView::Template::Error ( isn't precompiled)" is not helpful.

Any more thoughts on this from core? Definitely feels like current implementation is wrong, and I'm sure plenty of people would love to help out if given guidance.

Andrew White
Owner

One possible solution is to return a url of //:0 like this StackOverflow answer suggests if the path passed to asset_path is nil or blank. That way it passes the HTML validation tests and doesn't cause any server requests. On a related note we currently don't generate a blank alt attribute if one isn't specified and the path is a data uri or blank - should we?

Loïc Faure-Lacroix

@pixeltrix's suggestion seems good to me. A blank alt should be generated in any case where the alt has a "falsy" value. It can be empty but the alt has to be present to generate a valid "img" tag. And the //:0 seems to be a good alternative. But it has to be documented in some way. Because it might not be that clear of why a "falsy" src might return that url instead of an empty string or nothing.

Steve Klabnik
Collaborator

we currently don't generate a blank alt attribute if one isn't specified and the path is a data uri or blank - should we?

:+1:

Antoine Herzog

I had still the error message ..strange .

Steve Klabnik
Collaborator

@antoineherzog on which version of Rails?

Antoine Herzog
Steve Klabnik
Collaborator

@antoineherzog right. It was fixed on master, so it won't be fixed until 4.0.

Also, PLEASE make sure you've dealt with the recent security issue if you're on 3.2.8: https://groups.google.com/forum/?fromgroups=#!topic/rubyonrails-security/61bkgvnSGTQ

Antoine Herzog

ok thank you for your reply ! I will wait 4.0 ;)

Joe

Is there any reason the image_tag helper couldn't just plain return nil?

I override image_tag in my ApplicationHelper to do this

def image_tag(source, options = {})
  super(source, options) unless source.blank?
end

works perfectly for me

Thomas Buckley-Houston

Just chiming in with a "image_tag and blank string throws and error!?" (on rails 3.2.9). This really surprised me, and the error of "ActionView::Template::Error ( isn't precompiled)" is not helpful.

+1

idelahoz

it also, happens with audio_tag, it shouldnt send an error if you pass blank where an asset path is expected in no case, sometimes you wanna render that empty to fill it later with js code

Michael Yagudaev

+1. I think this violates the rails philosophy of no surprises.

Tad Hosford

+1, it's an annoyance.

Also happens on the octothorpe:

image_tag("#", class: "icon-download-alt", alt: "Download")

ActionView::Template::Error (# isn't precompiled)

Ruben Espinosa

I had partly the same problem, but in some cases in the data base I have null in the image path or the image does't exist, that is why I mixed the code of some people here, and here is my solution

  def image_tag(img , options={})
    path = "#{Rails.root}/app/assets/images/#{img}"
    img = "missing.png"  unless img.present? and File.file?(path)
    super(img, options)
  end

Now I validate if the path is "" and if the image exists

nleo
nleo commented March 12, 2014

+1 shoud not raise exeption

feng qijun

+1 should not raise exception. at least not throw "isn't compiled"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.