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.
Related
I have a Rails 3.1 app that uses the codebrew/backbone-rails. In a .jst.ejs template, I would like to include an image, like so:
<img src="<%= image_path("foo.png") %>"/>
But of course the asset helpers are not available in JavaScript.
Chaining ERB (.jst.ejs.erb) does not work, because the EJS syntax conflicts with ERB.
Here is what I know:
The asset helpers are not available in the browser, so I need to run them on the server side.
I can work around the problem by making the server dump various asset paths into the HTML (through data attributes or <script> and JSON) and reading them back in JS, but this seems rather kludgy.
Is there a way to somehow use the asset helpers in EJS files?
There is a way, actually, to chain a .jst.ejs.erb file, although it's fairly undocumented, and I only found it through looking at the EJS test cases. You can tell EJS to use {{ }} (or [% %] or whatever else you want) instead of <% %>, and then ERB won't try to evaluate your EJS calls.
Make sure to require EJS somewhere in your code (I just included gem 'ejs' in my Gemfile), and then create an initializer (I called it ejs.rb) that includes the following:
EJS.evaluation_pattern = /\{\{([\s\S]+?)\}\}/
EJS.interpolation_pattern = /\{\{=([\s\S]+?)\}\}/
Then just make sure to rename your templates to .jst.ejs.erb, and replace your existing <% %> EJS-interpreted code with {{ }}. If you want to use something other than {{ }}, change the regular expressions in the initializer.
I wish there were an option in Sprockets to handle this through the config rather than having to explicitly include EJS, but as of the moment, there's no way to do that that I know of.
I can see two ways. Neither are great.
When you say <%%= variable %> then this is rendered by ERB as <%= variable %>, so you could double percent escape everything but the asset_tags and that would survive the trip through one ERB pass on the way to EJS.
If you find that too gross...
How about making a different javascript file, with an ERB extension, that defines your asset paths? And then use the asset pipeline to require that.
So say assets.js.erb defines something like:
MyAssets = {
'foo': <%= image_path("foo.png") %>,
...
}
And then require this somewhere near the top of your manifest. And then reference the globals however that works in EJS.
For those willing to try HAML instead of EJS: Using haml-coffee through haml_coffee_assets has worked well for me as well.
You can have the following in a .hamlc.erb file:
%img(src="<%= image_path('foo.png') %>")
(It still doesn't give you routing helpers though, only asset helpers.)
Ryan Fitzgerald was kind enough to post a gist of his JavaScript asset helpers (which get precompiled with ERB): https://gist.github.com/1406349
You can use corresponding Javascript helper via the following gem:
https://github.com/kavkaz/js_assets
Finally (after installing and configuring) you will be able to use it like this:
<img src="<%= asset_path("foo.png") %>"/>
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.
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).
what is the best/most efficient way of creating dynamic CSS with Rails. I am developing an admin area on a site, where I would like a user to be able to customize the style of their profiles(Colour mostly), which will also be saved.
Would you just embed ruby script in the css file?
Would you need to change the file extension from css?
Thanks.
In Rails 3.1, you can have your stylesheets pre-processed by erb.
Now let's say you have some dynamic styling called dynamic.css.scss.erb (the .erb at the end is important!) in app/assets/stylesheets. It will be processed by erb (and then by Sass), and as such can contain stuff like
.some_container {
<% favorite_tags do |tag, color| %>
.tag.<%= tag %=> {
background-color: #<%= color %>;
}
<% end %>
}
You can include it like any stylesheet.
How dynamic should it be?
Note that it will be only processed once, though, so if the values changes, the stylesheet won't.
I don't think there is a super efficient way to do have it completely dynamic yet, but it is still possible to generate the CSS for all requests. With this caveat in mind, here's a helper for that in Rails 3.1:
def style_tag(stylesheet)
asset = YourApplication::Application.assets[stylesheet]
clone = asset.class.new(asset.environment, asset.logical_path, asset.pathname, {})
content_tag("STYLE", clone.body.html_safe, type:"text/css")
end
Here's how to use it:
First, copy the above helper in app/helpers/application_helper.rb.
You can then include it in your page as follows:
<% content_for :head do %>
<%= style_tag "dynamic.css" %>
<% end %>
The rest of your page.
Make sure that your layout uses the content :head. For example, your layout/application.html.erb could look like:
...
<HEAD>
....
<%= yield :head %>
</HEAD>
...
I found this out thanks to this post.
You can use ERB with CSS, you just need to render css in the controller. However, for such a heavily requested resource, I do not recommend generating this every time. I would store the users stylesheet in memcached or redis, and recall from it when the page loads, rather than rerendering the file each time. When they update their style, you can expire the cache, just make sure it gets rebuilt when the page renders.
There has been a lot of development over the years, and I recently figured out how to do what this question is asking. And since it has been about 9-10 years since someone has answered this, I thought that I would put in my 2 cents.
As others have said, it is not good practice, and thus can not be done, to put ruby code directly into the CSS file as the CSS is precompiled and is not able to be dynamically changed within the file.... BUT, it can be dynamically changed outside the file!
I will need to give a quick synopsis of CSS variables in case future readers do not know how to use them.
CSS has the use of variables within its coding language to make it easier to change a lot of elements at one time. You put these variables at the top of the CSS file in a root section. Like this:
:root {
--primary: #0061f2;
--secondary: #6900c7;
}
Now, anytime you want to style an element one of those colors, you can simply put var(--variableName) like this:
.btn{
color: var(--secondary);
background-color: var(--primary);
}
.h1 {
color: var(--primary);
}
You can see how it would then be much easier to change the variable in the root section and thus change all other instances within the CSS.
Now for the dynamic Ruby part.
In the <head> section of your application file (or in the case of this question the file that holds the template for the admin's dashboard), you will need to redeclare the CSS variables with your dynamic variables and mark them as important. For example, let's say that you allow your user to choose primary and secondary colors for their dashboard and they are stored in the user's profile called like: user.primary_color and user.secondary_color. You will need to add this to your <head> section:
<style>
:root{
--primary: <%= user.primary_color %> !important;
--secondary: <%= user.secondary_color %> !important;
}
</style>
This !important tag will override the variables found in the CSS file thus dynamically allowing the user to change the CSS and view of their dashboard and have it remain persistent (as the values are saved in their profile).
I hope that this helps future developers.
Happy Coding!
Currently there is a lot of options to generate dynamic css in rails.
You can use less css - is an extension to CSS with extra features.
Gem Less css for rails provides integration for Rails projects using the Less stylesheet language in the asset pipeline.
If you are using twitter bootstrap you may check this out less rails bootstrap.
Also you can use one more CSS extension language Sass for generating CSS. Here is a Saas rails gem.
Check out Dynamic CSS in Rails and Render Rails assets to string blog posts and article about Asset Pipeline
Related SO questions:
Best way to handle dynamic css in a rails app
Dynamic CSS in Rails asset pipeline, compile on fly
Rails: change CSS property dynamically?
I just built this for another site. I have a controller action and a view that pulls color values out of the database, then renders a customized CSS based on the current user's account. To optimize, I am using the built in Rails page caching, which stores a copy on disk and serves it as a static asset. Nice and fast.
Here's an example from the ERB code
#header { background: <%= #colors["Header Stripe Background"] %>; border: 1px solid <%= #colors["Header Stripe Border"] %>; }
#header h1 {color: <%= #colors["Headline Color"] %>; }
#header p a { background: <%= #colors["Control Link Background"] %>; color: <%= #colors["Control Links"] %>;}
#header p a:hover {background: <%= #colors["Control Link Hover"] %>; text-decoration:underline;}
This solution defines some constants in config/site_settings.rb, which can then be used throughout the Rails application, as well as for automatically generating the CSS files whenever the Rails app starts and the CSS input files have been modified..
http://unixgods.org/~tilo/Ruby/Using_Variables_in_CSS_Files_with_Ruby_on_Rails.html
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.