Using a variable in stylesheet - ruby-on-rails

I have a multi-tenancy Rails app, where each tenant has an base_color attribute which contains a hex color code. I have a variables.css.scss file which contains Sass variables which are used in several other stylesheet files.
Now I want to use the tenant.base_color variable to set the Sass variable $base_color in variables.css.scss, so the base color of the app changes according to the logged in tenant. Is this at all possible?
I tried to rename the file to variables.css.scss.erb and then use this:
$base-color: <%= current_tenant.base_color %>;
But this doesn't work, I get an File to import not found or unreadable: variables.css.scss. error.

It's not possible. css.scss files are compiled to css once (when you run bundle exec rake assets:precompile), so you can't make them dependant on some dynamic values. I guess you'd have to use inline css instead.

Related

Customizing Bootflat in Rails

I have installed bootflat using bower. The instaltion location was set up as "vendor/assets/components/Bootflat". I have also included the relevant files in my application.scss, application.js and application.haml files. I assume that it's being included correctly because everything is working as expected.
My question now is, how do I customize scss variables used in Bootflat? Here is my current code in application.scss (app/assets/stylesheets):
$alert-primary:red !important;
#import "Bootflat/bootflat/scss/bootflat";
"$alert-primary" is a variable that's already used by Bootflat and I want to redefine it. How/Where would I redefine this? I get that what I'm doing above is probably not right as the variable is defined by a Bootflat file, which would mean that my definition above is overwritten. But I also do not want to change the scss code in the origin files? What is the best solution? Will it be to copy and paste the code for a specific component into my app's stylesheet and then redefine a component after importing bootflat (this should overwrite the original definition by Bootflat)?

Rails 4 assets - two different digests getting generated

I clearly must be Doing Something Wrong here. I'm wrestling with the asset pipeline (again). I have a custom font, and it seems to me to get everything to compile properly I need to use asset_path() in multiple places, but it's having an unexpected effect.
I realize there are several ways to do this, but here's what I have currently:
In application.css.scss.erb:
#import "<%= asset_path("my-font.css") %>";
my-font.css's source file is app/assets/stylesheets/my-font.css.erb (it needs to be an .erb because I am also using asset_path() there as well).
In application.rb I am adding my-font.css to the precompile list.
config.assets.precompile << 'my-font.css'
When I clean out public/assets and run rake assets:precompile Everything's getting compiled, with digests, but the digest applied to the actual file is not the same as the digest calculated and put in to application.css.
The resulting file is
public/assets/my-font-2f25682a1ea904a866ef9f44101a5a2e.css but in public/assets/application-bba2edaee36771f4bdb5c89b8ec90aaf.css the reference to it is:
#import url(/assets/my-font-ed843d3b174ca427edf963e473ad9e9b.css);
I realize I'm probably using asset_path() more than I should, and also importing files via url() instead of requiring them, but this has gotten me the closest to having things working.
I suspect one of the digests is being calculated on my-font.css before it goes through ERB, and the other after, but I don't understand why nor how to fix it.
Suggestions?
I would guess that you're cleaning your assets just by emptying public/assets. That's not enough, you'll also need to empty your tmp/cache/assets, or just run rake assets:clobber to do both.
I've resolve this kind of dependency by injecting the raw contents of the asset you want to bundle into a composite asset like application.scss.erb. You need to explicitly declare the dependency (so that changes in my-fonts.css cause a regenerations of application.css) and then inject the contents:
application.scss.erb:
// Should be at Top of File
//= depend_on_asset my-fonts.css
//... wherever in the file you want the contents injected:
<%= environment['my-fonts.css'] %>
How does this work? During asset pipeline compilation, the environment here has a hash of all pre-compiled asset contents. This allows you to inject the compiled contents from my-fonts.css into your composite asset. Because we're manually injecting the value, we need to explicitly create a dependency to track this relationship via depend_on_asset.
One thing to keep in mind is that multiple asset pre-processors (SCSS, ERB, etc) are processed from the "outside in", so the contents of the my-fonts.css asset will be compiled/injected during the ERB processing as CSS output. They will be included within the asset before SCSS processing. This shouldn't pose a problem, because if this is an SCSS asset, any SCSS references will be compiled before injection into the parent asset.

SCSS import relative to an imported stylesheet?

I've installed foundation-rails in my Rails app and run rails g foundation:install. The project-specific file(s) (mostly foundation_and_overrides.scss) are properly installed. The gem is there and it had no trouble installing, and the dependencies (SASS, Compass) are also there. But I'm getting:
Error compiling CSS asset
SASS::SyntaxError: File to import not found or unreadable: global.
Originating from:
/Users/local/.rvm/gems/ruby-2.0.0-p353/gems/foundation-rails-5.0.2.0/vendor/assets/stylesheets/foundation/components/_accordion.scss:1
After investigating, I've discovered that _accordion.scss was #imported in the main foundation.scss file, located two directories up in stylesheets/:
#import 'foundation/components/accordion'
The "missing" file, _global.scss, meanwhile, is in that same directory. If I then change the #import code in _accordion.scss from #import 'global' to #import 'foundation/components/accordion', it clears and moves on to the next error (there are a lot of sub-imports here).
It's clear that what's happening is SASS is looking for _global.scss relative to the top stylesheet, foundation.scss, and not relative to the imported stylesheet asking for it (_accordion.scss).
I can't imagine this is a bug in Foundation/Foundation-Rails – this gem wouldn't work for anyone – and I don't want to modify the gem's contents myself.
So my question: do I have to change some SASS settings to allow #import relative to an imported stylesheet? I don't want to modify this gem to make it work (I'd like to allow for future updates to the gem).
Edit
Clarification of directory structure within the gem's vendor/assets/stylesheets directory:
foundation.scss
foundation/components/_accordion.scss
foundation/components/_global.scss
Edit 2
You can actually see the gem's code and structure on github
Edit 3
Thought I'd solved the problem, but I didn't: changing from an #import to a =require got rid of the errors, and included Foundation's CSS. But require does not import the SCSS functionality - variables, mixins - that Foundation provides. There's no way to change global values this way, or to retrieve them or the mixins from the main stylesheet or other #imported stylesheets.
It looks like Foundation thinks this is the best possible solution:
Manually add Foundation's stylesheet subdirectories (each of them) to SASS's :load_paths in the main block of application.rb:
config.sass.load_paths += [
"#{Gem.loaded_specs['foundation-rails'].full_gem_path}/vendor/assets/stylesheets/foundation/components",
"#{Gem.loaded_specs['foundation-rails'].full_gem_path}/vendor/assets/stylesheets/foundation/"
]

Rails 4 image-path, image-url and asset-url no longer work in SCSS files

Are we supposed to use something else aside from image-url and others in Rails 4? They return different values that don't seem to make sense. If I have logo.png in /app/assets/images/logo.png and I do the following, this is what I get:
image-url("logo.png") -> url("/images/logo.png") #obviously doesn't work
image-path("logo.png") -> "/images/logo.png"
asset-url("logo.png") -> url("/logo.png")
Of course none of these work because they need at least /assets in front.
UPDATE: Actually, I just noticed, how do I access images in Rails 4? I have an image at /app/assets/images/logo.png. But if I go to any of the following URLs, I still don't see my image:
http://localhost:3000/assets/logo.png
http://localhost:3000/assets/images/logo.png
http://localhost:3000/logo.png
http://localhost:3000/images/logo.png
UPDATE 2: The only way I can bring up my logo.png is by moving it into the /app/assets/stylesheets directory and then pulling up:
http://localhost:3000/assets/logo.png
I just had this issue myself.
3 points that will hopefully help:
If you place images in your app/assets/images directory, then you should be able to call the image directly with no prefix in the path. ie. image_url('logo.png')
Depending on where you use the asset will depend on the method. If you are using it as a background-image: property, then your line of code should be background-image: image-url('logo.png'). This works for both less and sass stylesheets. If you are using it inline in the view, then you will need to use the built in image_tag helper in rails to output your image. Once again, no prefixing <%= image_tag 'logo.png' %>
Lastly, if you are precompiling your assets, run rake assets:precompile to generate your assets, or rake assets:precompile RAILS_ENV=production for production, otherwise, your production environment will not have the fingerprinted assets when loading the page.
Also for those commands in point 3 you will need to prefix them with bundle exec if you are running bundler.
Your first formulation, image_url('logo.png'), is correct. If the image is found, it will generate the path /assets/logo.png (plus a hash in production). However, if Rails cannot find the image that you named, it will fall back to /images/logo.png.
The next question is: why isn't Rails finding your image? If you put it in app/assets/images/logo.png, then you should be able to access it by going to http://localhost:3000/assets/logo.png.
If that works, but your CSS isn't updating, you may need to clear the cache. Delete tmp/cache/assets from your project directory and restart the server (webrick, etc.).
If that fails, you can also try just using background-image: url(logo.png); That will cause your CSS to look for files with the same relative path (which in this case is /assets).
I just found out, that by using asset_url helper you solve that problem.
asset_url("backgrounds/pattern.png", image)
I had a similar problem, trying to add a background image with inline css. No need to specify the images folder due to the way asset sync works.
This worked for me:
background-image: url('/assets/image.jpg');
Rails 4.0.0 will look image defined with image-url in same directory structure with your css file.
For example, if your css in assets/stylesheets/main.css.scss, image-url('logo.png') becomes url(/assets/logo.png).
If you move your css file to assets/stylesheets/cpanel/main.css.scss, image-url('logo.png') becomes /assets/cpanel/logo.png.
If you want to use image directly under assets/images directory, you can use asset-url('logo.png')
for stylesheets:
url(asset_path('image.jpg'))
In case anyone arrives looking for how to generate a relative path from the rails console
ActionView::Helpers::AssetTagHelper
image_path('my_image.png')
=> "/images/my_image.png"
Or the controller
include ActionView::Helpers::AssetTagHelper
image_path('my_image.png')
=> "/images/my_image.png"

Using a database value in a LESS file in Rails

I have installed the less-rails gem as I am keen to use the colour manipulation LESS offers. I need to extract a colour from my database as my themes base colour, and build up from there.
I have the static CSS, and have renamed it styles.css.less to ensure that rails understands the less extension, which it appears to.
The next thing I tried was to also wrap the file as an erb, to hopefully allow ruby string literals to process before being sent to LESS, and eventually outputting as valid CSS (still with me?)
The file is now called style.css.less.erb. While the file simple contains valid CSS, the processing of the document works. As soon as I add a ruby string literal, it fails.
color: #{"#112233"};
In the chrome debugger, nothing after this line is getting processed.
What am I doing wrong, and how should I do what I am trying to do?
As Chowlett says in comments, you should use erb syntax: <%= "#112233" %>
Next step is get that value from db. If this color value is application-wide, probably you are looking for settings in db solution. I use rails-settings-cached gem for that. Your result code will looks like
color: <%= Setting.foo_color %>
If you are using assets on production, don't forget to recompile them after each setting change.
And if it's not a setting but probably something specific to each user then you can't use application-wide css files for that, but you can write inline css in views.

Resources