6

I'm trying to include Fontawesome with a Rails 4 app however the assets aren't making it into the asset pipeline. However, the fonts aren't making it out in production and I can't figure out why.

File structure organisation

All my assets are stored in /assets/components so that Fontawesome appears in: /assets/components/font-awesome (they're in a different directory because I'm using Bower).

CSS manifest file:

# application.css.scss
/* ...
*= require bootstrap/dist/css/bootstrap
*= require font-awesome/css/font-awesome
*= require_self
*= require_tree .
*/

Asset pipeline is set to precompile fonts

# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
config.assets.paths << Rails.root.join('vendor', 'assets', 'components')

# Adding Webfonts to the Asset Pipeline
config.assets.precompile << Proc.new { |path|
  if path =~ /\.(eot|svg|ttf|woff|otf)\z/
    true
  end
}

I added the precompile instructions so that the fonts would all be precompiled as per this question

Heroku 12 Factor gem is included

#gemfile
group :production do
  gem "rails_12factor"
end

So what's the problem?

When I push to Heroku, it shows that the application is requesting the files but that they're not loading:

enter image description here

enter image description here

And looking at the logs it seems to be a routing issue - I would have expected the font to be served from /assets/fonts but it is apparently looking in /fonts

   app[web.1]: Started GET "/fonts/fontawesome-webfont.ttf?v=4.0.1" for 86.161.231.181 at 2013-10-29 15:53:01 +0000
   app[web.1]: Started GET "/fonts/fontawesome-webfont.ttf?v=4.0.1" for 86.161.231.181 at 2013-10-29 15:53:01 +0000
   app[web.1]: 
   app[web.1]: ActionController::RoutingError (No route matches [GET] "/fonts/fontawesome-webfont.ttf"):

Why aren't the assets getting served

I'm a bit confused with all of this. Why aren't these fonts being served?

Community
  • 1
  • 1
Peter Nixey
  • 16,187
  • 14
  • 79
  • 133
  • It says 'No route matches [GET] "/fonts/fontawesome-webfont.ttf', but don't you want to load from /assets/fontawesome-webfont.ttf instead? In fontawesome.css, I've used url('../fontawesome-webfont.ttf') instead of url('fonts/fontawesome-webfont.ttf') – Amy.js Nov 04 '13 at 10:50
  • Hi @AmyHua. You're right however you shouldn't need to specify the individual font files. The manifest file and the single line `require font-awesome/css/font-awesome` should take care of all of the other files. Also the fonts do load correctly in development, it's just that something isn't resolving correctly for sprockets. – Peter Nixey Nov 04 '13 at 11:55
  • Heroku has an ephemeral file system, you can create files in a session but this is only a instance of your dyno, files will be not be presents on new sessions because will be new instances. Perhaps you should be sure than files are in your repo before push. – dani herrera Nov 07 '13 at 10:16

1 Answers1

16

This problem maybe caused by a reason that Rails assets can't precompile url() function in CSS file.

Because your fonts files are precompiled by assets, all urls point to these files must be rewritten to MD5-digested file name. Unfortunately Rails can't precompile url() automatically, at least I think so because I tested some cases and got this conclusion :) In Rails guide, Rails provides these functions using ERB and Sass. see here .

I think there are two ways to solve your problem.

The first, set directory in .bowerrc to public/components and use them manually, don't require them in your assets.

The second, I suggest to use font-url() instead of url() in Font-Awesome, so your application.css.scss will be looked like:

   /* ...
    *= require bootstrap/dist/css/bootstrap
    *= require font-awesome/css/font-awesome
    *= require_self
    *= require_tree .
    */    

    @font-face {
      font-family: 'FontAwesome';
      src: font-url('font-awesome/fonts/fontawesome-webfont.eot?v=4.0.3');
      src: font-url('font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.0.3') format('embedded-opentype'),
      font-url('font-awesome/fonts/fontawesome-webfont.woff?v=4.0.3') format('woff'),
      font-url('font-awesome/fonts/fontawesome-webfont.ttf?v=4.0.3') format('truetype'),
      font-url('font-awesome/fonts/fontawesome-webfont.svg?v=4.0.3#fontawesomeregular') format('svg');
      font-weight: normal;
      font-style: normal;
    }

Redefine the font-path with your actual font path and font-face with font-url() , this function is provided by sass-rails. After precompile, you will see your url has been rewritten to /assets/font-awesome/fonts/fontawesome-webfont-50b448f878a6489819d7dbc0f7dbfba0.eot?v=4.0.3 or something like in public/assets/application-xxxxxx.css.

You can find the same approach in various gems which include assets for example bootstrap-sass, it's a very popular gem. read this file: _glyphicons.scss. You will see:

@font-face {
  font-family: 'Glyphicons Halflings';
  src: font-url('#{$icon-font-path}#{$icon-font-name}.eot');
  src: font-url('#{$icon-font-path}#{$icon-font-name}.eot?#iefix') format('embedded-opentype'),
       font-url('#{$icon-font-path}#{$icon-font-name}.woff') format('woff'),
       font-url('#{$icon-font-path}#{$icon-font-name}.ttf') format('truetype'),
       font-url('#{$icon-font-path}#{$icon-font-name}.svg#glyphicons_halflingsregular') format('svg');
}

url() has been replaced. So I think rewrite @font-face in application.css.scss is the simplest way :)

By the way, bootstrap and font-awesome both have @font-face. I don't know whether font-awesome is necessary.

When you access the page, it shows the correct log. So you don't need change any code in bower repositories. Hope it helps.

Bigxiang
  • 6,252
  • 3
  • 22
  • 20
  • HI Xiang. This is awesome, thank you for spending so much time on it. It's very frustrating that this is the type of solution that's needed. I wondered whether the `font-url()` declarations were the problem. There's so much required for the fix though that I almost wonder whether it's easier to simply put the files into the directories and ignore bower. It seems a shame but it also actually seems easier. What do you think is more maintainable? – Peter Nixey Nov 08 '13 at 16:59
  • Hi Peter, I have improved the answer, please have a look. I think if there is a gem for assets can be used, using the gem will be more maintainable. Bower can be used to include javascript and css without `url()` easily. – Bigxiang Nov 09 '13 at 00:22
  • I am also having the same problem with Rails, bower/bower-rails and font-awesome/bootstrap fonts. @Bigxiang your solution worked fine but I am still confused whether something is not set up properly or this is the right (unfortunate) way to accomplish this. – Radolino Dec 16 '15 at 11:14