Rails 4 fonts not working on production - ruby-on-rails-4

I am trying to use fonts Awesome on my Rails 4 application. The fonts works very well on Development, But on Production is not working.
Assets are precompiled on the server while deploying with capistrano.
All CSSs files, JS (at app/assets/* and vendor/assets/*) are working... only fonts are not.
If I run the application on my development machine as production, it works:
RAILS_ENV=production bin/rails s -b 0.0.0.0
Only when I send to my production host (VPS with Passenger+Ngnix), that the fonts dont works
what I have is:
# config/initializers/assets.rb
# Add additional assets to the asset load path
# Rails.application.config.assets.paths << Emoji.images_path
Rails.application.config.assets.precompile << /\.(?:svg|eot|woff|woff2|ttf)\z/
And...
# config/environments/production.rb
# ...
config.assets.compile = true
Ad finally:
# app/assets/stylesheets.css.erb
#font-face {
font-family: 'FontAwesome';
src: url("<%= font_path('Font-Awesome/fontawesome-webfont.eot') %>?v=4.3.0");
src: url("<%= font_path('Font-Awesome/fontawesome-webfont.eot') %>?#iefix&v=4.3.0") format('embedded-opentype'),
url("<%= font_path('Font-Awesome/fontawesome-webfont.woff2') %>?v=4.3.0") format('woff2'),
url("<%= font_path('Font-Awesome/fontawesome-webfont.woff') %>?v=4.3.0") format('woff'),
url("<%= font_path('Font-Awesome/fontawesome-webfont.ttf') %>?v=4.3.0") format('truetype'),
url("<%= font_path('Font-Awesome/fontawesome-webfont.svg') %>?v=4.3.0#fontawesomeregular") format('svg');
font-weight: normal;
font-style: normal;
}
The fonts are located at: vendor/assets/fonts/Font-Awesome/fontawesome-*
What I dont understand is that on Development it works and I have another app on Heroku with the same configuration and the fonts works very well.
If I go to my server using SSH and run ls my_app/public/assets, I can see all my assets (css, javascripts and fons) pre-compiled.
What I am missing?

I tried a lot of solutions, but nothing worked..
The only one that works was move the folder "fonts" from vendor/assets to app/assets.
This don't make sense to me, as I know, third-party assets must go to vendor/assets folder.
But the third CSS and Javascript files, are located at vendor/assets/* and works fine. Only fonts files that wont work.

Related

Cant generate all.css file from sass files with flask-assets

I became tired of using css in my flask app so I decided to move to scss with flask assets https://github.com/miracle2k/flask-assets.
I added this in my app.py file:
from flask_assets import Environment, Bundle
assets = Environment(app)
assets.debug = True
assets.url = app.static_url_path
scss = Bundle('sass/foo.scss', 'sass/bar.scss', filters='pyscss', output='gen/all.css')
assets.register('scss_all', scss)
If I understand correctly, these lines are supposed to go check my static/sass folder and generate a gen folder with a single all.css minified file right ?
I also created a sass folder inside my static assets folder and foo.scss file inside it with some code to test it out.
However when I launch the app, nothing is generated and I get no error. What am I doing wrong here ?
Here is how I got it to work.
Here is a screen shot of my project directory before it generates anything:
Next, I made sure I had the following installed:
pip install flask-assets
pip install pyscss (this is your filter in the filters='pyscss' section)
Here is how I have the code setup:
from flask import Flask, render_template
from flask_assets import Environment, Bundle
app = Flask(__name__)
assets = Environment(app)
assets.url = app.static_url_path
assets.debug = True
scss = Bundle('sass/foo.scss', 'sass/bar.scss', filters='pyscss', output='gen/all.css')
assets.register('scss_all', scss)
#app.route('/')
def hello_world():
return render_template('index.html')
if __name__ == '__main__':
app.run()
And the index.html:
{% assets "scss_all" %}
<link rel="stylesheet" href="/static/gen/all.css">
{% endassets %}
<ul>
<li>
Test Flask Assets
</li>
</ul>
Now, when I ran the application it took a sec for it to generate the css, but it did generate. Once it does, here is the directory structure after running:
And you can see in the chrome debugger that it indeed does load:
It's important to note that the folder has to be gen in the configuration output='gen/all.css' otherwise it won't work.
EDIT
Also per #David's comment, it's important that you have all the required scss files created to generate the output.

In Rails 4, how can I have a Rake task minify my assets?

I need to export a subset of my assets to some external sites. I've created a rake task to do that:
rake build:navbar
The problem is I cannot get the assets library to minify my library. Here's the code from my task method:
desc "Build navbar assets and markup for other sites."
task navbar: :environment do
# Set environment to production so pipeline will minify assets.
Rails.env = "production"
# Some setup code removed...
# How do we coax assets into minifying files?
Rails.application.config.assets.prefix = "../build/navbar/staging"
Rails.application.config.assets.js_compressor = :uglifier
Rails.application.config.assets.css_compressor = :sass
Rails.application.config.assets.digest = false
Rails.application.config.assets.compress = true
Rails.application.config.assets.debug = false
Rails.application.config.assets.paths = [Rails.root.join('/app/assets/javascripts'),
Rails.root.join('/app/assets/stylesheets/navbar')]
Rails.application.config.assets.precompile = ['navbar.js', 'navbar.css']
# Compile now.
Rake::Task['assets:clean'].invoke
Rake::Task['assets:precompile'].invoke
# Cleanup code removed...
end
It will generated a compressed version of my assets (navbar.css.gz), but not a minified version (navbar.min.css).
I've googled this up and down and it seems like this recipe of settings should do the trick. What am I missing?
I think I've identified the underlying problem. The assets pipeline task, i.e. sprockets-rails, doesn't fully respect config settings. It seems to override some settings depending on the Rails environment. And you can't simply change the Rails environment within a rake task.
The goal, again, is to port a subset of the Rails application's assets for another project using this rake command:
rake build:navbar
Here's some sample code that shows how I worked around these issues:
namespace :build do
desc "Build navbar assets and markup."
task navbar: :environment do
# Prep Builder
builder = Navbar::Builder.new(target: target)
builder.prep_build
# Why this? Setting Rails.env or ENV['RAILS_ENV'] didn't work.
system("rake build:navbar_assets RAILS_ENV=production")
builder.generate_markup_file
builder.move_output_files_to_build_directory
builder.cleanup
end
desc "Build navbar assets."
task navbar_assets: :environment do
# Configure the asset pipeline to compile minified files.
# NOTE: Sprockets only minifies files in production environment (or won't
# do it in development) so this assumes RAILS_ENV is set to production
# on the command line.
Rails.application.config.assets.prefix = "../build/navbar/staging"
Rails.application.config.assets.paths = [Rails.root.join('app/assets/javascripts'),
Rails.root.join('app/assets/stylesheets')]
Rails.application.config.assets.precompile += ['navbar.js', 'navbar.css']
# Let it rip.
Rake::Task['assets:clobber'].invoke
Rake::Task['assets:precompile'].invoke
end
end
There were also some issues with file-path-building in the code in the question. Those have been corrected.

fontawesome + rails 4.0.1 not working

I am using fontawesome 3.2.1 and bootstrap 3.0.0 in my rails 4.0.1 project. All my assets are located in vendor/assets.
the problem is that my fontawesome is working in development mode when when i compile my assets(production env) and run the server in production env, its not able to load fontawesome. the errors are as
Started GET "/assets/fontawesome-webfont.svg" for 127.0.0.1 at 2014-01-08 11:48:55 +0530
ActionController::RoutingError (No route matches [GET] "/assets/fontawesome-webfont.svg"):
actionpack (4.0.1) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call'
actionpack (4.0.1) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
the assets are as
$ls vendor/assets/
=> fonts images javascripts stylesheets
$ls vendor/assets/*
=> vendor/assets/fonts:
FontAwesome.otf fontawesome-webfont.ttf glyphicons-halflings- regular.svg
fontawesome-webfont.eot fontawesome-webfont.woff glyphicons-halflings- regular.ttf
fontawesome-webfont.svg glyphicons-halflings-regular.eot glyphicons-halflings-regular.woff
vendor/assets/images:
bg_direction_nav.png bxslider search-icon.jpg
vendor/assets/javascripts:
bootstrap bxslider fancybox others revolution_slider
vendor/assets/stylesheets:
bootstrap bxslider fancybox font_awesome others revolution_slider
$ls vendor/assets/stylesheets/bootstrap/
=> bootstrap.min.css
$ls vendor/assets/stylesheets/font_awesome/
=> font-awesome.css
my application.css is as
$cat app/assets/stylesheets/application.css
/*
* This is a manifest file that'll be compiled into application.css, which will include all the files
* listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the top of the
* compiled file, but it's generally better to create a new file per style scope.
*
*= require bootstrap/bootstrap.min.css
*= require others/theme.css
*= require others/bootstrap-reset.css
*= require font_awesome/font-awesome.css
*= require bxslider/jquery.bxslider.css
*= require fancybox/jquery.fancybox.css
*= require revolution_slider/rs-style.css
*= require revolution_slider/settings.css
*= require others/flexslider.css
*= require others/style.css
*= require others/style-responsive.css
*= require_self
*/
fontawesome are loaded in font-awesome.css as
#font-face {
font-family: 'FontAwesome';
src: url('/assets/fontawesome-webfont.eot?v=3.2.1');
src: url('/assets/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'), url('/assets/fontawesome-webfont.woff?v=3.2.1') format('woff'), url('/assets/fontawesome-webfont.ttf?v=3.2.1') format('truetype'), url('/assets/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg');
font-weight: normal;
font-style: normal;
}
glyphicons are loaded in bootstrap.min.css as
#font-face{
font-family:'Glyphicons Halflings';
src:url('/assets/glyphicons-halflings-regular.eot');
src:url('/assets/glyphicons-halflings-regular.eot?#iefix') format('embedded-Opentype'), url('/assets/glyphicons-halflings-regular.woff') format('woff'),url('/assets/glyphicons-halflings-regular.ttf') format('truetype'),url('/assets/glyphicons-halflings-regular.svg#glyphicons-halflingsregular') format('svg')}
i did try couple of solution like prepending 'font' or 'assets' to 'url' but none worked.
--UPDATE
contents of config/application.rb
config.assets.enabled = true
config.assets.version = '1.0'
config.assets.paths += ["#{config.root}/vendor/assets/fonts", "#config.root}/app/assets/images/**", "#{config.root}/vendor/assets/images"]
config.assets.precompile += %w(*.png *.jpg *.jpeg *.gif *.eot *.svg *.ttf *.otf *.woff vendor/assets/stylesheets/**/* vendor/assets/fonts/*)
["#{config.root}/vendor/assets/javascripts", "#config.root}/vendor/assets/stylesheets"].each do |d|
config.assets.precompile += Dir.glob("#{d}/*").map{|f| "#{f.gsub(d + '/', '')}/**/*" if File.directory?(f)}.compact
I solved the problem as specified below.
1) Firstly, dont refer assets inside .css file. Rename the file to .css.scss. Thats the same extension whenever u create controller and it creates assets for that controller.(javascript and css). There are multiple applications to convert css to scss. Use them if the css is large.
2) use font-path whenever you want to refer a font inside a stylesheet. ie. use methods provided by rails to refer to assets rather than using 'src'
eg
#font-face {
font-family: 'MuseoSans-700';
src: url(font-path('museoSans/244DD4_0_0.eot'));
src: url(font-path('museoSans/244DD4_0_0.eot?#iefix')) format('embedded-opentype');
src: url(font-path('museoSans/244DD4_0_0.woff')) format('woff');
src: url(font-path('museoSans/244DD4_0_0.ttf')) format('truetype');
}
In the above code, my file is as "app/assets/stylesheets/fonts.scss" and my fonts are located in
$ls vendor/assets/fonts/
fontawesome museoSans museoSans500
$ls vendor/assets/fonts/museoSans
244DD4_0_0.eot 244DD4_1_0.ttf 244DD4_2_0.woff 244DD4_4_0.eot 244DD4_5_0.ttf 244DD4_6_0.woff 244DD4_8_0.eot 244DD4_9_0.ttf
244DD4_0_0.ttf 244DD4_1_0.woff 244DD4_3_0.eot 244DD4_4_0.ttf 244DD4_5_0.woff 244DD4_7_0.eot 244DD4_8_0.ttf 244DD4_9_0.woff
244DD4_0_0.woff 244DD4_2_0.eot 244DD4_3_0.ttf 244DD4_4_0.woff 244DD4_6_0.eot 244DD4_7_0.ttf 244DD4_8_0.woff
244DD4_1_0.eot 244DD4_2_0.ttf 244DD4_3_0.woff 244DD4_5_0.eot 244DD4_6_0.ttf 244DD4_7_0.woff 244DD4_9_0.eot
3) During asset precompilation, the helpers like 'font-path' or 'asset-path' help in pointing to the right asset. ie. if u specify it as
src: url('/assets/museoSans/244DD4_0_0.eot'));
this is still going to be the same in the compiled asset. it should ideally be
src: url('/assets/museoSans/244DD4_0_0-67652745236457645234dghfhsagfd64354.eot'));
You can 'grep' and check out the compiled file in "public/assets".
4) another way of making sure the assets are loading is the to call them from url.
5) Please set 'config.assets.compress = false' in your production or staging env file and run the application locally in prod/staging env so as the check the views to make sure that the assets are loading.
You can checkout https://github.com/joshsoftware/website/commit/859f2709180e9fb0aac59549d64bd4351a2842b3 commit for more understanding.
Your svg doesn't seem to be compiled, the fingerprint seems missing except if you set:
config.assets.digest = false
I was getting the same " no routes match GET" after precompiling. you can try to add the svg here in your config/application.rb:
config.assets.precompile += %w(*.svg)
And then retry a:
rake assets:precompile RAILS_ENV=production
In my case a simple rake assets:precompile wasn't enough i needed to specify the RAILS_ENV and RAILS_GROUPS (If the version of rails is lower than 4).
Normally the compiled assets are found in the public/assets directory.
I hope it helps
UPDATE:
Another idea coming from my experience with ckeditor with rails 4 in production. The assets compilation with digest is not working (https://github.com/galetahub/ckeditor). You need to add a rake task that copies/modify some files in the public/assets directory after compilation. Here is the code:
namespace :ckeditor do
desc 'Create nondigest versions of some ckeditor assets (e.g. moono skin png)'
task :create_nondigest_assets do
fingerprint = /\-[0-9a-f]{32}\./
for file in Dir['public/assets/ckeditor/contents-*.css', 'public/assets/ckeditor/skins/moono/*.png']
next unless file =~ fingerprint
nondigest = file.sub fingerprint, '.' # contents-0d8ffa186a00f5063461bc0ba0d96087.css => contents.css
FileUtils.cp file, nondigest, verbose: true
end
end
end
# auto run ckeditor:create_nondigest_assets after assets:precompile
Rake::Task['assets:precompile'].enhance do
Rake::Task['ckeditor:create_nondigest_assets'].invoke
end
You can easily replace ckeditor with fontawsome.

Django Admin not working / ugly - serving with nginx and gunicorn

I have nginx, gunicorn, django running on Ubuntu EC2 instance. The entire site operates fine. Except for the admin. The admin isn't displaying properly. I ran "python manage.py collectstatic" and edited the STATIC_ROOT and STATIC_URL. When I load the admin page, it's ugly, but when I inspect the source, the CSS files are located they should be
<title>Site administration | Django site admin</title>
<link rel="stylesheet" type="text/css" href="http://staticfiles.mydomain.com/static/admin/css/base.css" />
<link rel="stylesheet" type="text/css" href="http://staticfiles.mydomain.com/static/admin/css/dashboard.css" />
I can look at the nginx access.log and see the files are getting requested and delivered, but the page does not display properly. It's like the files are being received but not processed. Error log is clean.
SOLVED
Under the console tab in Chrome Developer Tools I noticed the following:
Resource interpreted as Script but transferred with MIME type text/plain: "http://staticfiles.<mydomain>.com/static/admin/js/jquery.min.js".
So the files were getting delivered to browser, but it didn't know what to do with them. To fix it I had to edit the nginx.conf and specify the default type for a couple directories ...
location /static/admin/js/ {
default_type text/javascript;
alias /home/ubuntu/webapps/<myproject>/static/admin/js/;
}
location /static/admin/css/ {
default_type text/css;
alias /home/ubuntu/webapps/<myproject>/static/admin/css/;
}
That fixed it; the django admin loads the stylesheets and javascript files and looks and operates normally. I hope this helps someone else.
My Solve ;
1.step
settings.py edit
from django.conf.global_settings import TEMPLATE_CONTEXT_PROCESSORS as TCP
STATIC_ROOT = "/opt/venv/myDjangoProject/static/"
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
'django.contrib.staticfiles.finders.FileSystemFinder',
)
TEMPLATE_CONTEXT_PROCESSORS = TCP + (
'django.core.context_processors.request',
)
2.step
run collesctstatic in terminal :)
python manage.py collectstatic
The proper way to solve this is to add include /etc/nginx/mime.types; in the http section of the nginx configuration file.

How to use django-compressor with apache?

I'm been using Django Compressor to manage my coffee/less files and its great for development, but I've had some issues to make it work for my production deployment.
My idea is to have apache to host the static files, possibly in another server. I'm setting COMPRESS_OFFLINE = True on the settings.py file.
Then I do the following
python manage.py compress - This populates the CACHE directory in my static directory, where all static files will be collected.
python manage.py collectstatic - This collects static files from all the apps on my project (some of which don't use compressor) into my static directory.
Copy the static directory somewhere to be hosted with apache. And setup apache to serve the files.
Modify the static_url variable in the settings.py file to point to the static server.
If I open any page, I get the following error on my server, this only seems to happen when I have DEBUG = False and COMPRESS_OFFLINE = True on my settings.py file:
TemplateSyntaxError: Caught OfflineGenerationError while rendering:
You have offline compression enabled but key
"777ba26736d046ab043dc151e7e9a060" is missing from offline manifest.
You may need to run "python manage.py compress".
When I check the static/CACHE directory, I confirm what the error says, this is my manifest.json file:
{
"6189b8598993d1cbdbd35d4dfd1a6711": "<script type=\"text/javascript\" src=\"http://192.168.1.123/CACHE/js/2f6ca6616bd6.js\"></script>",
"5c66dbed0e5b766c6e32773cd8585f3c": "<link rel=\"stylesheet\" href=\"http://192.168.1.123/CACHE/css/154d95903951.css\" type=\"text/css\" />"
}
If I delete the CACHE directory and rerun python manage.py compress, I get a new set of ID's both on the error message and the manifest file, but the ID on the error is still missing on the manifest.
So, I guess there are two questions here. Why is it not working? What is the proper way to achieve this?
Thanks.
If you've run compress, and you still get the message
OfflineGenerationError: You have offline compression enabled but key "4971a40e3b459a8cda8287a7f7caa96d" is missing from offline manifest. You may need to run "python manage.py compress"
then it's likely you have dynamic content inside compress tags. Make sure that compress is always the innermost block, and that there are no tags inside the compress block.
I guess you're using django-compressor 1.1.2 which doesn't support static template tag {% static "..." %}.
Try installing the dev version of django-compressor with:
pip install django_compressor==dev
It should solve the problem.
David Wolfe is absolutely right: had to dig throught all the code of mine to get rid of {% trans... etc.
I make it like this:
<script>
window.__enter_email = "{% trans "Enter correct email" %}"
window.__url = "{% url "shop:go" %}"
</script>
{% compress js %}
<script>
$("#bla")..... window.__enter_email ...
</script>
{% endcompress %}
Hope, helps someone!