21

Placed fonts in app/assets/fonts

Added

Add the fonts path
config.assets.paths << Rails.root.join('app', 'assets', 'fonts')

Precompile additional assets
config.assets.precompile += %w( .svg .eot .woff .ttf )

in production.rb and development.rb

Fonts linked in css like:

@font-face {
  font-family: 'Icomoon';
  src:url('/assets/icomoon.eot');
  src:url('/assets/icomoon.eot?#iefix') format('embedded-opentype'),
    url('/assets/icomoon.svg#icomoon') format('svg'),
    url('/assets/icomoon.woff') format('woff'),
    url('/assets/icomoon.ttf') format('truetype');
  font-weight: normal;
  font-style: normal;
}

Seems to work in development. But in HEROKU is does not seem to work. It cannot find /assets/icomoon.eot .

The solution in this link does not seem to work

Using fonts with Rails asset pipeline

Community
  • 1
  • 1
Sarvesh
  • 1,152
  • 2
  • 11
  • 25

11 Answers11

31

Assets like fonts will work on development but not production if you are using regular old css to locate your assets rather than the asset pipeline helpers. Rails 4 added breaking changes to the asset pipeline to encourage people to use it properly, and not use the old css method of referencing assets.

To resolve this, you need to use the new asset pipeline helpers to point to the fingerprinted, cached versions of your fonts. Rather than url (which does not use the asset pipeline), you need to use font-url (which does use it). To do this, you may have to use Sass or embed ERB in your stylesheet.

Example (using SCSS):

@font-face {
  font-family: 'Icomoon';
  src: font-url("/assets/icomoon.eot");
  src: font-url("/assets/icomoon.eot?#iefix") format("embedded-opentype"), font-url("/assets/icomoon.svg#icomoon") format("svg"), font-url("/assets/icomoon.woff") format("woff"), font-url("/assets/icomoon.ttf") format("truetype");
  font-weight: normal;
  font-style: normal;
}

See here: http://guides.rubyonrails.org/asset_pipeline.html#coding-links-to-assets

Aaron Gray
  • 11,283
  • 7
  • 55
  • 61
  • Thanks, worked for me too. Just make sure that this is put in a `.css.scss` file though - I got caught out trying to put this in `application.css` which didn't work, understandably. – zelanix Aug 04 '14 at 18:00
  • 2
    I tried this with Rails 4.2 and it works with Heroku. Doesn't even have to add this code: `config.assets.precompile += %w( .svg .eot .woff .ttf )` – hsym Jul 06 '15 at 14:25
13

In light of the comments received on this answer (and the unnecessary downvotes) I've amended my answer as follows:

It seems Rails has now created a way to handle fonts in the assets folder. It's called font-path and works like this:

If you add a custom font to your /assets/fonts folder, you can use the font-path helper to access the files within. This can then be used in your stylesheets & other assets using the font-path helper:

|-app/
|---assets/
|-----fonts/
|-----images/
|-----javascripts/
|-----stylesheets/

@font-face {
  font-family:'icofonts';
  src:font-url('icofonts.eot');
  src:font-url('icofonts.eot?#iefix') format('embedded-opentype'),

  ...
} 

This works for precompiled assets (which Heroku does anyway), and static assets. If you want the pre-Rails 4 way of achieving this, please refer to my answer below:


We've got fonts working on Heroku here: http://firststop.herokuapp.com (it's in demo still)

Here is our CSS for it:

#assets/application.css
/*-- Akagi Font --*/
@font-face {
    font-family: 'akagi';
    src: url('fonts/akagi-th-webfont.eot'),
    src: url('fonts/akagi-th-webfont.eot?#iefix') format('embedded-opentype'),
         url('fonts/akagi-th-webfont.woff') format('woff'),
         url('fonts/akagi-th-webfont.ttf') format('truetype'),
         url('fonts/akagi-th-webfont.svg#akagithin') format('svg');
    font-weight: 300;
    font-style: normal;

}
@font-face {
    font-family: 'akagi';
    src: url('fonts/akagi-bk-webfont.eot');
    src: url('fonts/akagi-bk-webfont.eot?#iefix') format('embedded-opentype'),
         url('fonts/akagi-bk-webfont.woff') format('woff'),
         url('fonts/akagi-bk-webfont.ttf') format('truetype'),
         url('fonts/akagi-bk-webfont.svg#akagibook') format('svg');
    font-weight: 400;
    font-style: normal;

}
@font-face {
    font-family: 'akagi';
    src: url('fonts/akagi-sb-webfont.eot');
    src: url('fonts/akagi-sb-webfont.eot?#iefix') format('embedded-opentype'),
         url('fonts/akagi-sb-webfont.woff') format('woff'),
         url('fonts/akagi-sb-webfont.ttf') format('truetype'),
         url('fonts/akagi-sb-webfont.svg#akagisemibold') format('svg');
    font-weight: 500;
    font-style: normal;

}

We put our fonts into the /stylesheets/fonts folder

We just do the standard precompile fonts stuff to get all CSS working on Heroku, and it works. I suspect your paths are not correct. Maybe try moving your fonts directory into your /assets/stylesheets folder :)

Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • I'm going to assume this works, as it seems to be the most thorough answer. :p I have to give the bounty to someone, enjoy! :-d – nicohvi Oct 18 '13 at 07:40
  • Oh okay :) Yep, I should have mentioned the RAILS_ENV=production stuff actually – Richard Peck Oct 18 '13 at 08:23
  • 2
    This will work fine for older versions of Rails, but it DOES NOT use the asset pipeline, and it may not work at all on versions of Rails 4 because you are using static versions of the files, which Rails 4 made breaking changes around. To utilize the benefits of the asset pipeline and ensure compatibility with newer versions of Rails, you need to use the asset pipeline helpers - see my answer if you need a reference point. – Aaron Gray Oct 18 '13 at 16:56
  • 1
    This is not a solution to the question asked. All this does is place the files into the public folder and allow nginx/static server to serve the files. Whilst this will work, it totally misses the point of using the asset pipeline and as Aaron above mentioned, it suggests solving the issue in a way that isn't Rails friendly. – Lawrence Jones Apr 23 '14 at 00:26
  • 1
    Both you and Aaron are wrong. The asset pipeline places the files into the public folder when you precompile. Heroku itself [recommends you use what I've recommended](https://devcenter.heroku.com/articles/rails-4-asset-pipeline#dependencies-improperly-used). What you're trying to do is load precompiled "fingerprinted" assets, which can only be accessed using the various path helpers. This works for us in production, I'm sure your tests have found a similar result – Richard Peck Apr 23 '14 at 06:47
  • Hi Rick - very helpful...2 quick questions. 1. What is the point of this line? src:font-url('icofonts.eot?#iefix') format('embedded-opentype'), 2. Using font-url breaks this in localhost. Did you find a way to get this working in dev and prod? I have everything you have in your code except that line i just asked about. Is that necessary for heroku? – brad May 02 '14 at 18:40
9

Actually, I just tried the solution proposed in this comment, and it worked perfectly. Seems you only have to change the regex for the precompile instruction in order for Heroku to correctly find the asset.

i.e. change config.assets.precompile += %w( .svg .eot .woff .ttf ) to config.assets.precompile << /\.(?:svg|eot|woff|ttf)$/.

Edit: It might also be necessary to add RAILS_ENV=production when you run the assets:precompile rake task, as per Heroku's docs.

Community
  • 1
  • 1
nicohvi
  • 2,270
  • 2
  • 28
  • 42
  • out of curiosity, why the `?:` and not simpler `/\.(svg|eot|woff|tff)$/` – AJcodez Dec 08 '13 at 05:17
  • the ?: is so the contents of the () are not captured. Both are the same, the only difference is that without the ?: the value of the matched string will be stored here $~[1] – chopi321 Apr 01 '14 at 08:09
  • Your edit saved my night! I was running assets:precompile without the prod env and my CSS files weren't picking up the fingerprinted FONT files. – Kevin Zych Sep 19 '14 at 03:40
3

Rails 4

# config/application.rb
config.assets.paths << Rails.root.join("app", "assets", "fonts")
config.assets.precompile += %w(.svg .eot .woff .ttf)

# app/assets/stylesheets/foundation-icons.css.scss
@font-face {
  font-family: "foundation-icons";
  src: asset-url("foundation-icons.eot");
  src: asset-url("foundation-icons.eot?#iefix") format("embedded-opentype"),
       asset-url("foundation-icons.woff") format("woff"),
       asset-url("foundation-icons.ttf") format("truetype"),
       asset-url("foundation-icons.svg#fontcustom") format("svg");
  font-weight: normal;
  font-style: normal;
}
araslanov_e
  • 309
  • 2
  • 5
2

Try removing /assets/ from all of your font paths.

@font-face {
  font-family: 'Icomoon';
  src:url('icomoon.eot');
  src:url('icomoon.eot?#iefix') format('embedded-opentype'),
    url('icomoon.svg#icomoon') format('svg'),
    url('icomoon.woff') format('woff'),
    url('icomoon.ttf') format('truetype');
  font-weight: normal;
  font-style: normal;
}

Also try removing scaffolds.css if it's in assets/stylesheets.

Jeremy Green
  • 8,547
  • 1
  • 29
  • 33
  • This did not work. I just uploaded the fonts to S3 for the time being. – Sarvesh Oct 13 '13 at 20:02
  • 1
    @sarvesh careful with the fonts on s3 (even if the bucket is cname'd to a subdomain), you're going to need to turn CORS on for them to work in firefox across domains. – Gabe Kopley Oct 16 '13 at 21:26
2

I solved the problem by using a combination of all the answers and comments. My example uses the Foundation Icon Fonts.

In your application.rb file add the following:

config.assets.precompile << /\.(?:svg|eot|woff|ttf)$/

Rename your application.css file to application.css.scss and use the font-url and asset-path directives:

@font-face {
  font-family: "foundation-icons";
  src: font-url( asset-path("foundation-icons.eot") );
  src: font-url( asset-path("foundation-icons.eot?#iefix") ) format("embedded-opentype"),
       font-url( asset-path("foundation-icons.woff") ) format("woff"),
       font-url( asset-path("foundation-icons.ttf") ) format("truetype"),
       font-url( asset-path("foundation-icons.svg#fontcustom") ) format("svg");
  font-weight: normal;
  font-style: normal;
}
Dex
  • 12,527
  • 15
  • 69
  • 90
2

You don't actually have to change the precompile regex or asset path. Try to run rake assets:precompile in production mode before committing to Heroku.

rake assets:precompile RAILS_ENV=production

and make sure to reference your assets in css files using asset_path helper method.

like:

src: font-url('<%= asset_path("foundation-icons.eot")%>');
1
  1. Rename your .css file to .css.erb
  2. Replace all the url('/assets/icomoon.eot') with url(<%= asset_path 'icomoon.eot' %>), etc.

You can achieve the same result by converting your css file to SASS/SCSS and using font-url() helper instead of url().

I've tried that with Rails 4 and it works even without the bits you've added to production.rb/application.rb.

mrt
  • 1,669
  • 3
  • 22
  • 32
  • This is what is also needed, however you don't need to use `<%= asset_path … %>`. You can just use the SASS directive `asset-path(…)` – Dex Apr 04 '14 at 21:29
1

You don't need to include the /assets/fonts/ directory in config.assets.paths. According to documentation all directories included in app/assets, lib/assets or vendor/assets are automatically loaded.

http://guides.rubyonrails.org/asset_pipeline.html#asset-organization

Pipeline assets can be placed inside an application in one of three locations: app/assets, lib/assets or vendor/assets.

[...]

Besides the standard assets/* paths, additional (fully qualified) paths can be added to the pipeline in config/application.rb.

config.assets.paths << Rails.root.join("lib", "videoplayer", "flash")

Try to run Rails.application.class.config.assets.paths in console and you'll see an array of all directories inside /assets. if you add another directory and restart the console it will be automatically included inside the array and the content will be served as assets.

You don't even need config.assets.precompile += %w( .svg .eot .woff .ttf ) because all non-js-css files are already included through the default matcher Proc.

http://guides.rubyonrails.org/asset_pipeline.html#precompiling-assets

The default matcher for compiling files includes application.js, application.css and all non-JS/CSS files (this will include all image assets automatically):

[ Proc.new { |path| !%w(.js .css).include?(File.extname(path)) }, /application.(css|js)$/ ]

Try to only add the fonts directory in app/assets/ leaving all config as default and deploy your app on heroku.

Community
  • 1
  • 1
marquez
  • 737
  • 4
  • 10
  • This helped me. Also, for the `font-url`, I removed any path additions. `src: font-url('Something.otf')` – Baub Jan 06 '14 at 04:26
1

After trying all the methods above, none worked for me but this is how I fixed my font problem. If the fonts work in development mode then simply do

config.assets.compile = true

in

config\environments\production.rb
Cyrus
  • 84,225
  • 14
  • 89
  • 153
Shawn
  • 26
  • 4
0

There are two ways to solve this issue.

  1. You can directly put your font files in public directory and add the path e.g /fonts/font-name in the CSS file
  2. Add the line Rails.application.config.assets.compile = true in config/initializers/assets.rb file