How can I access Rails objects in Sass? - ruby-on-rails

In a Rails 3.1.0 project, I have Companies with a few customizable attributes like background_color and link_color. I want to be able to set some Sass variables like so:
$background_color: <%= #company.background_color %>
$link_color: <%= #company.link_color
...
This doesn't work because #company is nil when Sass does its thing. I'm not sure how to go about solving this in a way that's dynamic (companies can be created and colors can be changed and the views update immediately). Any suggestions?

I can think of a couple approaches off the top of my head:
Serve your stylesheet through a controller.
Use CSS classes to configure the colors and serve just that CSS through a controller, inlined partial, or a CSS #import.
Serving your stylesheet through a controller is pretty straightforward so there's not much to say. This might be a bit ugly and cumbersome.
For the second one, you'd add a couple extra CSS classes:
.custom-bg {
background-color: some-default-bg;
}
.link-fg {
color: some-default-fg;
}
/*...*/
Then any element that need to use the custom background color would need their usual CSS classes and custom-bg; similar shenanigans would be needed for the other configurable values. To supply the customized CSS, you could inline a <style> element into your HTML using a standard ERB partial or you could serve the CSS through a controller (either through <style src="..."> or #import). So you'd fake the SASSy goodness with old school multiple CSS classes in your HTML.
There's also JavaScript. You'd need some way to identify the elements that need their colors adjusted and then adjust them directly with things like this:
$('.need-custom-background').css('background-color', '...');

I think you might be able to do something just like what you have there, but you need to change the extensions of the files to '.css.scss.erb'

To follow up on this, I did create a stylesheet controller but it was rather contrived to get Sass parsing and asset pipeline load paths all working correctly. I ended up dumping that and reorganizing the styles so I could generate a static stylesheet for each company which gets regenerated and uploaded to S3 on company update.

Well, if you mean a dynamic object like a model loaded via a controller, you can't really, at least not very easily. This is because unlike HTML ERB templates, the SASS ones are generally rendered once and served statically unless something changes in the code or they are re-precompiled via rake (depending on your environment configs). But you can access some helper methods, global objects, and use some ruby in there by renaming the file with an "erb" extension e.g. application.css.scss.erb. See
https://guides.rubyonrails.org/asset_pipeline.html#coding-links-to-assets
How can I use Ruby/Rails variables inside Sass?)
If you need styles based on dynamically loaded objects, like models, you can...
Write CSS styles literally in the template
Compile the stylesheets dynamically. See the top-rated answer here: How do I create dynamic CSS in Rails?
For some use cases you might accomplish the same thing by leveraging Rails/SASS's import path hierarchy (i.e. SASS #import 'partial_name_with_no_path' will search the importing SASS files folder first and then fall back to the top level - You can configure this as well).

Related

In Rails, how can I include a style sheet from the asset pipeline as a <style> tag?

Everyone knows how to use stylesheet_link_tag to link to a stylesheet, but I would like to actually include an entire stylesheet in a page itself. (No, this is normally not a great practice, but it makes sense in this context.)
stylesheet_include_tag does not exist, and a co-worker who is a much bigger bad-ass at Rails than I am says there isn’t a simple way.
Question:
Is it actually possible to make use of the asset pipeline and still embed the contents of a CSS or JavaScript file (compiled from Sass or CoffeeScript!) into a .haml view? How?
Added for clarity:
I’d like for my layout to be able to include something like:
= stylesheet_link_tag "base"
= stylesheet_embed_tag "page-specific-styles/foo"
And have this generate output HTML along these lines:
<link rel="stylesheet" href="/base.css" />
<style type="text/css">.foo { color: red; }</style>
Update
It’s possible to use Sass within Haml if you set your initalizer correctly, but I cannot seem to #import "foo" from this context, where foo.css.sass is a stylesheet in the asset pipeline. Note that #import "compass" (assuming you have the compass gem) does work.
This looks like (haml):
%style
:sass
#import "foo"
Rails gives an error that "foo" cannot be found, even though it claims to be looking in app/assets/stylesheets (which is where foo.css.sass lives).
So, this feels closer, but still not quite there.
from http://blog.phusion.nl/2011/08/14/rendering-rails-3-1-assets-to-string/ :
YourApp::Application.assets.find_asset('api.css').source
in haml
%style
=raw YourApp::Application.assets.find_asset('foo.css').source
caveats:
I believe this requires asset compilation in production, which can be pretty costly.
If I understand your question correctly, you could add your CSS code to a normal Ruby view file (as a partial), say styles.html.erb.
And then add that to your page upon any condition you want, I think it's the simplest way of looking at it.

How do I prevent scaffold.css from overriding my custom css?

I can't figure it out. It's probably trivial but I am extremely new to rails.
Thanks in advance if you can help!
Answer:
I went to the generated file that adds the header to my pages and changed the included css file to my own custom one.
In Rails 3.1 it would work a litte bit different since only the application style is included by default.
Since there is a list of all further included ones like mentioned here: Rails 3.1 Load css in particular order, you just have to change the order of this list or add the file at a specific position.
There's a question about not using scaffold.css, might be what you're looking for?
Rails scaffold without the css file?
It's not the most beautiful css, but in css you can add '!important' after an statement to override all 'normal' css statements. So you would use something along the lines of:
border:0px !important;
in your css.
Have the CSS file with the correct styling you want applied to load last.
Or as others have suggested you could add !important to the css in question if you cant change the load order of the css files.
body {
color:#FFFFFF!important;
}

Where in the Rails framework should I place my Backbone templates?

I'm a rails developer trying to learn Backbone and then I ran into this problem: since Underscore templates include symbols like <%=%>, I guess templates can't be included into erb files, so is it okay to have a rails partial for every single template? And what extension should it be?
You can escape the erb symbols by using two % in the opening tag, and put your backbone templates in the rails views:
<script type='text/template' id="my-template'>
<%%= name %>
</script>
will output the following in your page:
<script type='text/template' id="my-template'>
<%= name %>
</script>
Putting your Backbone templates directly in your rails views is IMHO the best option when you're trying to learn. You're already wrestling with the new concepts, no need to add another hurdle.
Starting with Rails 3.1, it provides two things that make working with Backbone templates a little easier: the asset pipeline, and automatic JST (JavaScript Template) compilation.
Create a directory in your app/assets folder called templates. This directory will automatically be picked up by the asset pipeline.
Next, name the files in that directory with an extension of jst and the type of template you are creating ejs (embedded javascript). You can even nest them in directories. For example:
app/assets/templates/my_template.jst.ejs
app/assets/templates/bookmarks/show.jst.ejs
The asset pipeline also allows you to use other templating languages like embedded coffeescript, mustache, handlebars, etc. by simply changing the file extension (and including any necessary gems).
Now to reference your JST templates in your Backbone views, simply use the path to the filename:
var Bookmark = Backbone.View.extend({
template: JST['bookmarks/show'],
render: function() {
this.$el.html(this.template(this.model.attributes));
return this;
}
});
You may need to add this line to your application.js:
// require_tree ../templates
Here's a nice article which explains all of this in a little more detail: http://www.bigjason.com/blog/precompiled-javascript-templates-rails-3-1
Where should you put your Backbone templates? I'd say nowhere. I believe that in most Rails applications, the server should be responsible for all rendering of HTML, while the client-side JavaScript should just be responsible for inserting that rendered HTML into the DOM. Among other things, this makes I18n easier.
The exception would be if Rails is simply being used as a lightweight backend for an application that runs mostly on the client side (though in that case, you might want to use Sinatra or something instead). In this case, Rails should probably render nothing, and have the JS do all the rendering.
Notice the underlying principle here. Either the server should be responsible for all rendering, or the client should. Splitting it will make life harder.

Rails Routing INSIDE CSS

Is there any way I can route assets inside of my css to where the rest of the views are pulling them? I mean, inside the CSS can I call url_for or css_for or something like that in order to have the images go through the assets router?
Thank you in advance!
You can use a controller action to render your CSS (with an erb template) and set the content type to text/css.
Take a look at this blog post from Josh Susser on dynamically generated stylesheets. It is from 2006 but the technique described is still applicable.

Possible to use stylesheet.css.erb in Rails?

Hey, I'm new to Rails and Ruby in general. I was wondering if it's possible to use an embedded ruby css file (css.erb), similar to using html.erb files for views.
For example, I'm using
<%= stylesheet_link_tag "main" %>
to link to my main.css file in public/stylesheets, but when I change the file extension from main.css to main.css.erb, it no longer renders the css..
Is this even possible, or is there a better way?
By the time this question was answered there was indeed no way to use .css.erb files in rails properly.
But the new rails 3.1 asset pipeline enables you to use asset helpers inside your css file. The css parsers is not binded a controller/action scope, but the ruby parser is now able to resolve some issues like image path references
.class { background-image: url(<%= asset_path 'image.png' %>) }
or embed an image directly into your css
#logo { background: url(<%= asset_data_uri 'logo.png' %>) }
source: http://guides.rubyonrails.org/asset_pipeline.html
You can also generate a "stylesheets" controller
./script/generate controller stylesheets main admin maintenance
You get something like this:
exists app/controllers/
exists app/helpers/
create app/views/stylesheets
exists test/functional/
exists test/unit/helpers/
create app/controllers/stylesheets_controller.rb
create test/functional/stylesheets_controller_test.rb
create app/helpers/stylesheets_helper.rb
create test/unit/helpers/stylesheets_helper_test.rb
create app/views/stylesheets/main.html.erb
create app/views/stylesheets/admin.html.erb
create app/views/stylesheets/maintenance.html.erb
And you can later use the app/views/stylesheets/ files as dynamically rendered css files.
The same method works for javascript files (javascripts controller)
I dont think so. Whats your intention - to use variables and have them be evaluated at runtime, or "compile" time (meaning like deploy time?). Also, what would be the ERB binding? Would it bind to the controller, like views and helpers are, so that ERB instance would have access to the instance variables set in the controller? I just pose this question as more of a theoretical exercise.
If you want to use variables in your CSS than you can use Haml's SASS. You dont get access to the controller's scope but you do get basic variables and looping. Plus other cool stuff like mixins.

Resources