How to refer to rails assets from stylesheets? - ruby-on-rails

I have a background image:
app/assets/images/bg.jpg
It works ok in development with the stylesheet as:
body {
background: #111 url('bg.jpg') repeat-x;
color: #DDD;
font: normal 90% "Trebuchet MS",Verdana,sans-serif;
margin-left: 1.2em;
}
But in production it doesn't show and the logs show:
ActionController::RoutingError (No route matches [GET] "/assets/bg.jpg"):
When I am using html and js templates I can add .erb to add the rails pre-processing that will let me use things like paths and helpers, e.g. images_url
How can I either:
a) Do a similar thing with my stylesheet
b) Use a path that works in both dev and prod. I tried [nothing] and images/ and they didn't work.

In the newer versions of rails, when you have a .css.scss stylesheets you have available a couple of helpers that will help you achieve that (you don't have to use .erb at all) like image-path and image-url (please take a look at the helpers section here https://github.com/rails/sass-rails)
basically what you need to do to get it working is replace
background: #111 url('bg.jpg') repeat-x;
for this
background: #111 image-url('bg.jpg') repeat-x;
and thats it. (also add the scss extension if you haven't already)

Precompile
You'll want to make use of the asset_path_helpers, specifically asset_url with one of the Rails asset preprocessors (SCSS / SASS)
The problem you'll have in production is that Rails appends what's known as a "fingerprint" to the assets. This fingerprint serves to define the uniqueness of the precompiled files:
Fingerprinting is a technique that makes the name of a file dependent
on the contents of the file. When the file contents change, the
filename is also changed. For content that is static or infrequently
changed, this provides an easy way to tell whether two versions of a
file are identical, even across different servers or deployment dates.
This means that when you push to production (and by virtue, precompile) the assets, you'll end up with the "bg.png" in a totally different location than that which you're referencing in the standard file.
--
Helpers
The trick is to use a dynamic path helper with the preprocessors:
#app/assets/stylesheets/application.css.scss
body {
background: #111 asset-url('bg.jpg') repeat-x;
color: #DDD;
font: normal 90% "Trebuchet MS",Verdana,sans-serif;
margin-left: 1.2em;
}
This should work for you

The fix that worked for me was to have
background: #111 url('<%= image_path "bg.jpg" %>') repeat-x;
and name my file .erb as in default.scss.css.erb
The other approaches didn't work.

Related

Don't show background images on Heroku. But local is working

My tag:
= link_to '', root_path, class: 'items__footage'
My selector:
.items__footage {
display: inline-block;
content: '';
width: 300px;
min-height: 300px;
background: url('/assets/footage_still.png') no-repeat;
background-size: auto 100%;
}
The path of my image is assets/images/footage_still.png. If I indicate this path, my image does not work locally.
I have done rake assets:precompile. But it did not help.
if you can use ruby code in your css file then use items_footage's background like this.
background: url("<%= asset_path('footage_still.png') %>");
To use ruby code inside css file make that file as filename.css.erb
From the documentation
In the production environment Sprockets uses the fingerprinting scheme
outlined above. By default Rails assumes assets have been precompiled
and will be served as static assets by your web server.
During the precompilation phase an SHA256 is generated from the
contents of the compiled files, and inserted into the filenames as
they are written to disk. These fingerprinted names are used by the
Rails helpers in place of the manifest name.
So, in production all your assets will be precompiled and will be served from public/assets. Also the file will be renamed with a fingerprint. So actually In production your file name will look something like
footage_still-908e25f4bf641868d8683022a5b62f54.png
The fingerprint will changes every time the file content changes and is useful for caching the static assets, generally called cache busting.
So when you hard code the image url /assets/footage_still.png, it will break in production. To handle the situation, rails provides something called asset url helpers.
To make it work, you have to rename your .css file to .scss if not and change.
background: url('/assets/footage_still.png') no-repeat;
to
background: image_url('footage_still.png') no-repeat;
Hope this helps.
You can use image_url('footage_still.png') and let rails find the path of the image

Rails: How to reference images in CSS within Rails 4

There's a strange issue with Rails 4 on Heroku. When images are compiled they have hashes added to them, yet the reference to those files from within CSS don't have the proper name adjusted. Here's what I mean. I have a file called logo.png. Yet when it shows up on heroku it is viewed as:
/assets/logo-200a00a193ed5e297bb09ddd96afb953.png
However the CSS still states:
background-image:url("./logo.png");
The result: the image doesn't display. Anybody run into this? How can this be resolved?
Sprockets together with Sass has some nifty helpers you can use to get the job done. Sprockets will only process these helpers if your stylesheet file extensions are either .css.scss or .css.sass.
Image specific helper:
background-image: image-url("logo.png")
Agnostic helper:
background-image: asset-url("logo.png", image)
background-image: asset-url($asset, $asset-type)
Or if you want to embed the image data in the css file:
background-image: asset-data-url("logo.png")
Don't know why, but only thing that worked for me was using asset_path instead of image_path, even though my images are under the assets/images/ directory:
Example:
app/assets/images/mypic.png
In Ruby:
asset_path('mypic.png')
In .scss:
url(asset-path('mypic.png'))
UPDATE:
Figured it out- turns out these asset helpers come from the sass-rails gem (which I had installed in my project).
In Rails 4, you can reference an image located in assets/images/ in your .SCSS files easily like this:
.some-div {
background-image: url(image-path('pretty-background-image.jpg'));
}
When you launch the application in development mode (localhost:3000), you should see something like:
background-image: url("/assets/pretty-background-image.jpg");
In production mode, your assets will have the cache helper numbers:
background-image: url("/assets/pretty-background-image-8b313354987c309e3cd76eabdb376c1e.jpg");
The hash is because the asset pipeline and server Optimize caching
http://guides.rubyonrails.org/asset_pipeline.html
Try something like this:
background-image: url(image_path('check.png'));
Goodluck
In css
background: url("/assets/banner.jpg");
although the original path is /assets/images/banner.jpg, by convention you have to add just /assets/ in the url method
None of the answers says about the way, when I'll have .css.erb extension, how to reference images. For me worked both in production and development as well :
2.3.1 CSS and ERB
The asset pipeline automatically evaluates ERB. This means if you add an erb extension to a CSS asset (for example, application.css.erb), then helpers like asset_path are available in your CSS rules:
.class { background-image: url(<%= asset_path 'image.png' %>) }
This writes the path to the particular asset being referenced. In this example, it would make sense to have an image in one of the asset load paths, such as app/assets/images/image.png, which would be referenced here. If this image is already available in public/assets as a fingerprinted file, then that path is referenced.
If you want to use a data URI - a method of embedding the image data directly into the CSS file - you can use the asset_data_uri helper.
.logo { background: url(<%= asset_data_uri 'logo.png' %>) }
This inserts a correctly-formatted data URI into the CSS source.
Note that the closing tag cannot be of the style -%>.
Only this snippet does not work for me:
background-image: url(image_path('transparent_2x2.png'));
But rename stylename.scss to stylename.css.scss helps me.
WHAT I HAVE FOUND AFTER HOURS OF MUCKING WITH THIS:
WORKS :
background-image: url(image_path('transparent_2x2.png'));
// how to add attributes like repeat, center, fixed?
The above outputs something like: "/assets/transparent_2x2-ec47061dbe4fb88d51ae1e7f41a146db.png"
Notice the leading "/", and it's within quotes.
Also note the scss extension and image_path helper in yourstylesheet.css.scss. The image is in the app/assets/images directory.
Doesn't work:
background: url(image_path('transparent_2x2.png') repeat center center fixed;
doesn't work, invalid property:
background:url(/assets/pretty_photo/default/sprite.png) 2px 1px repeat center fixed;
My last resort was going to be to put these in my public s3 bucket and load from there, but finally got something going.
Referencing the Rails documents we see that there are a few ways to link to images from css. Just go to section 2.3.2.
First, make sure your css file has the .scss extension if it's a sass file.
Next, you can use the ruby method, which is really ugly:
#logo { background: url(<%= asset_data_uri 'logo.png' %>) }
Or you can use the specific form that is nicer:
image-url("rails.png") returns url(/assets/rails.png)
image-path("rails.png") returns "/assets/rails.png"
Lastly, you can use the general form:
asset-url("rails.png") returns url(/assets/rails.png)
asset-path("rails.png") returns "/assets/rails.png"
Interestingly, if I use 'background-image', it does not work:
background-image: url('picture.png');
But just 'background', it does:
background: url('picture.png');
In some cases the following can also be applier
logo { background: url(<%= asset_data_uri 'logo.png' %>) }
Source: http://guides.rubyonrails.org/asset_pipeline.html
You can add to your css .erb extension. Ej: style.css.erb
Then you can put:
background: url(<%= asset_path 'logo.png' %>) no-repeat;
When using gem 'sass-rails', in Rails 5, bootstrap 4, the following worked for me,
in .scss file:
background-image: url(asset_path("black_left_arrow.svg"));
in view file(e.g. .html.slim):
style=("background-image: url(#{ show_image_path("event_background.png") })");
This should get you there every single time.
background-image: url(<%= asset_data_uri 'transparent_2x2.png'%>);
By default Rails 4 will not serve your assets. To enable this functionality you need to go into config/application.rb and add this line:
config.serve_static_assets = true
https://devcenter.heroku.com/articles/rails-4-asset-pipeline#serve-assets
In Rails 4, simply use .hero {
background-image: url("picture.jpg");
} in your style.css file as long as the background image is tucked in app/assets/images.
This worked for me:
background: #4C2516 url('imagename.png') repeat-y 0 0;

How to include twitter bootstrap in my Rails project manually (without using any gems)?

I'm learning Rails and want to play with Rails and Twitter Bootstrap. My Rails project layout is:
├─assets
│ ├─images
│ ├─javascripts
│ └─stylesheets
├─controllers
├─helpers
├─mailers
├─models
└─views
├─course
└─layouts
The Twitter Bootstrap layout is:
├─css
├─img
└─js
I know Bootstrap css file references its image file, such as:
[class*=" icon-"] {
display: inline-block;
width: 14px;
height: 14px;
*margin-right: .3em;
line-height: 14px;
vertical-align: text-top;
background-image: url("../img/glyphicons-halflings.png");
background-position: 14px 14px;
background-repeat: no-repeat;
margin-top: 1px;
}
So they must retain there relative position, or I have to change the CSS file. I want to know, if I don't want to use any Bootstrap related gems, what's the best way to place these Bootstrap files into my Rails project? Thanks.
First, you should probably move the Bootstrap source files to their appropriate locations in the assets folder in your Rails app - that is, CSS files in the stylesheets folder, JS in javascripts, and images in images.
As mentioned already, you'll need to change paths to images in Bootstrap's CSS. However, you'll need to make use of Rails' asset path helpers if you plan on using your app in production.
For example, background-image: url('../images/glyphicons-halflings.png'); is absolutely incorrect when using the asset pipeline. This will work fine in development, but as soon as you pre-compile assets for a production environment things won't work - Rails appends fingerprints to asset file names for caching purposes, which makes the URL above incorrect.
The correct way to code paths in your assets is outlined in the Rails Guide for the Asset Pipeline. If you're using CSS only, you should add the .erb extension to your filename (to get bootstrap.css.erb) and do something like this:
background-image: url(<%= asset_path 'glyphicons-halflings.png' %>);
If you are using SASS/SCSS, you can also use the built-in asset-path or image-path helpers. Again, this is mentioned in the guide I linked to above.
In the end, you probably should be using a gem, as this work will already be done for you. But, if you must, this should work well enough. Of course, if you ever want to update Bootstrap, you'll have to do this again.
I ran into the same trouble, and didn't want to have to install gems, etc.
There's a much easier solution.
Just override the icon selectors for background image in your custom CSS.
[class^="icon-"], [class*=" icon-"] {
background-image: url("/assets/img/glyphicons-halflings.png");
}
[class^="icon-white"], [class*=" icon-white"] {
background-image: url("/assets/img/glyphicons-halflings-white.png");
}
Put the glyphicons PNGs in app/assets/images/img/ (or wherever you want) and you're done.
You have to change every Glyphicons icon to the assets path. That's a lot of work. Also you have to use LESS, so the easiest way to use bootstrap with rails is using a gem. This is the gem that I use gem 'twitter-bootstrap-rails' this gem also includes font awesome so check this too
Redirect calls in routes.rb
get '/img/:name', to: redirect {|params, req| "/assets/#{params[:name]}.#{params[:format]}" }
This will redirect calls for /img to /assets
You can put the css and js files anywhere in your project as they don't reference each other, however, you will have to update the glypicon references in the css file.
In your case:
background-image: url("../images/glyphicons-halflings.png");
EDIT: I updated the path. I originally included "assets" which is incorrect with your given directory structure.

Background images do not render on Ruby on Rails application

I am attempting to have a image render in the background of a div with the class head.
My application view is written Haml and the body is defined as follows:
%body
.container
.head
.sixteen_columns
.top-nav
Included in my application stylesheet is:
.head {
background-image: url(/images/background_image.jpg);
width: 100%;
height: auto;
}
I have tried a number of variations to specify the path of the image and altered the image name several times but to no avail.
What is the issue?
Consider using the asset_path helper when referencing images in your stylesheet. Documentation may be found here (check out 2.2.1)In the context the CSS you listed you would heave
.head {
background-image:url(<%= asset_path 'background_image.jpg'%>);
width:100%;
height:auto;
}
Note: This requires that your style sheet be an erb.
Doing so offers a number of advantages over explicitly stating the path, one being that as the structure of rails application changes with new version releases, you will not need to change anything in your code in order for that image to be referenced properly.
This may seem like overkill just to reference an image but it's one of the many conventions of Rails that are difficult to get used but great! as your application grows and changes, hopefully enabling it to better endure the test of time.
Assuming you're using Rails 3.1 or beyond, and that you're using the asset pipeline properly for your images, you can include your image file by doing the following:
.head {
background-image: url(/assets/background_image.jpg);
width: 100%;
height: auto;
}
The reason for this is because of the way the asset pipeline works. It compiles your assets at run time and it places all of your assets in a folder called /assets/. It also ignores subfolder structuring and it just dumps everything into the root /assets/ folder, not /assets/subfolder/.
Try running
rails -v
from the console to confirm what version of Rails you're on.
It sounds like you're running a rails 2.x application, correct? That should mean that you're serving images, js etc from the /public directory. One important gotcha that tripped me up setting background images in css is that the paths you specify are relative to the directory the stylesheet is in(e.g /public/stylesheets), not the root directory of the project itself.
Have you tried changing the path to go up one directory from where the stylesheet is located?
.head {
background-image: url(../images/background_image.jpg);
width: 100%;
height: auto;
}
EDIT: What other paths to the bg image have you tried?
Some other possibilities could be:
background-image: url(images/background_image.jpg);
background-image: url('../images/background_image.jpg');
One other thing to check would be to load the view and examine the div in Google Chrome using the inspector (Ctrl Shift + I). Select the div and examine the styles Chrome is assigning to it.
Also, double check that it's still named background_image.jpg Can't tell you how many times I've gotten burned by some typo I overlooked ;)
Solution:
It turned out to be a combination of two things. I used this format for the background image:
background-image: url(../images/background_image.jpg);
However, the .head div was renbdering with a height of 0. I added a fixed height to test, and it all showed up perfectly. I can work with this from here.
Thank you all so much for the help!!
In rails 4 you can now use a css and sass helper image-url:
div.logo {background-image: image-url("logo.png");}
If your background images aren't showing up consider looking at how you're referencing them in your css files.

Maintain RTL version of stylesheets with rails asset pipeline

Background
I want to enable right-to-left locales as well as left-to-right, but I only want to maintain a single set of stylesheets.
The idea is that calling application-rtl.css will serve a rtl-converted version of application.css (using r2).
This functionality has two use-cases:
development: serve dynamically, converting on the fly
production: have precompilation generate the -rtl versions (extending rake assets:precompile task)
So far, I've managed to implement a RTLConverter that enables me to serve all my stylesheets converted to RTL without having touched them at all:
config/initializers/rtl_converter.rb:
require "r2"
require "tilt"
class RTLConverter < Tilt::Template
def prepare; end
def evaluate(context, locals, &block)
R2.r2 #data
end
end
Rails.application.assets.register_preprocessor 'text/css', RTLConverter
You can also implement this as an engine for sprockets to only convert files having the .rtl extension:
Rails.application.assets.register_engine 'rtl', RTLConverter
My question
How can I hook into the asset pipeline in order to:
serving an on-the-fly converted version of any stylesheet with the name-postfix '-rtl' (look for the file without the postfix and serve a converted version of that)?
creating converted copies with the name-postfix '-rtl' of all stylesheets during precompilation
Notes:
The converter does not work in conjunction with the sass engine, but seems to work fine with less. It's been applied to a twitter-bootstrap based site and works like a charm.
The converter has not been tested in production.
If I can find a decent solution to this problem, I intend to create and maintain a gem and give it back to the community.
I would aim for just using CSS directly to handle the LTR-RTL differences. CSS can probably handle the job for you. In case you define your CSS as LTR, then, based on a CSS class you can override the stuff you want.
Per default, define your entire CSS stylesheet as LTR.
Put an extra css class on the body which handle the locale. For instance <body class="RTL">
Define all exceptions to the default by overriding with CSS classes prefixed by "RTL"
A short example. Original "default" styles:
body { direction: ltr; }
.sidebar { width: 200px; float: right; margin-left: 30px }
Then, overwrite relevant styles later in your css:
body.rtl { direction: rtl; }
.rtl .sidebar { float: right; margin-right: 30px; }
/*remember to 'reset' all defaults for example: */
.rtl .sidebar { margin-left: 0; }
With sass, you have a common place to define standard variables, for instance margin in the example above. Your mileage may vary. But to me, that sounds more simple than messing with asset pipeline.
Unfortunately, none of the other answers really suggested the solution I was looking for, so after digging into matters, I was able to come up with a simple gem that could flip the stylesheet based on the filename.
So by including that gem and serving up a version of the stylesheet with '-flipped' appended to the name, I am now able to serve an automatically flipped version both in dev and production.
Find the gem on rubygems.org: stylesheet_flipper
Find a usage description on gihub: monibuds/stylesheet_flipper
As far as I can tell, Sprockets does not expose any hooks into the path lookup mechanism to processors. Even if it did, I don't think you could invoke some generalized "read asset" method.
All in all, I fear that making AP do what you want would require some serious arm-twisting.
So here's a completely different idea. What if you:
Dropped on-the-fly asset processing altogether, even in development
Had a Guard task set up to
recompile assets when their sources change (I think this exists already)
generate the RTL versions of the compiled CSS
Push the compiled assets to production (gasp!)
In other words, maybe you could trade some of the AP features for increased flexibility?
(I'm not going for the bounty here because this is just an idea, not a solution)
Wrote about this issue a year ago:
http://amitkazmirsky.com/2011/05/29/dry-your-rtl-and-ltr-css-files-in-rails-with-sass/
Basically my approach was to write the css with direction as variables:
#user-box {
backgroud-color: white;
padding: 0 5px;
float: $dir;
}
#side-nav {
margin-#{$opdir}: 5px;
}

Resources