I am working on a Rails 3.1 app and am happily using SASS and CoffeeScript. I particularly like the SASS extensions of variables and imports. I have constructed a single _global-settings.css.scss file which contains ALL of the hex constant values I use throughout all of my stylesheets. This gives me a single place to manage colors, fonts and layout dimensions. Very DRY.
But, if I wish to use JQuery to tweak my css dynamically, I no longer have access to my css compile-time variables, and must reproduce the same data as a JSON hash in a .js.coffee file. Not DRY at all.
Here is my question: Before I go off and build a rake task to munge my css settings file into an equivalent CoffeeScript hash, does anyone have a more clever idea? Like hiding all the values in a hidden div in an html file?
You'd have an easier time moving your CSS configuration into Ruby and then sending your _global-settings.css.scss and a small piece of CoffeeScript through ERB. Then you have your settings in place and you can access them everywhere.
Somewhere in Ruby you'd have this:
CSS_SETTINGS = {
:text_color => '#333',
:text_color_hilite => '#f33',
:font_size => '14px',
#...
}
Then rename your _global-settings.css.scss to _global-settings.css.scss.erb and use things like this inside it:
$text-color: '<%= CSS_SETTINGS[:text_color] %>';
// ...
And inside a global_settings.js.coffee.erb you could have this:
window.app.global_settings = <%= CSS_SETTINGS.to_json.html_safe %>
You could even write a simple view helper that would SASSify a Hash:
def sassify(h)
h.map do |k, v|
# You might want more escaping for k and v in here, this is just
# a simple proof of concept demo.
[ '$', k.to_s.gsub('_', '-'), ': ', "'#{v}'", ';' ].join
end.join("\n")
end
and then you could say this in your _global-settings.css.scss.erb:
// Import global CSS settings.
<%= sassify(CSS_SETTINGS).html_safe %>
You could also monkey patch a to_sass into Hash and use CSS_SETTINGS.to_sass but that's probably taking things one step too far.
Related
I am afraid that this question is simply stupid, but... is there any option to use SASS variables in rails .erb files?
I defined a few colors in my variables.css.scss and I wish to use their values in my views or helpers in Rails. Maybe Rails can see some compiled sass resources or something?
Thank you for answers!
You can do it the other way around, ie using ruby code in your css/sccs code. It's a bit tricky, but it may help you :
First declare the color as a ruby constant :
# Put this into config/initializers/constants.rb for example
module Constants
FOO_COLOR = '#123456'
end
Next, rename the variables.css.scss into variables.css.scss.erb and use the constant created at the previous step
$fooColor: <%= Constants::FOO_COLOR %>
Finally use the color in your other scss files
#import "_variables";
#foo {
background-color: $fooColor;
}
And you can also use the Constants::FOO_COLOR in your Rails code too.
Be careful, you may be using precompiled assets in production. It will work with a constant as shown below, but it won't work if you want to change the value, or get it from a DB.
I've got somefile.js.coffee.erb file which is processed by Rails asset pipeline. My ERB code returns some string that cannot be parsed by Coffee which result in SyntaxError exception. I would like to peek into generated somefile.js.coffee file, or in general any intermediary file processed by asset pipeline.
I've tried to examine Sprockets with no luck:
environment = Sprockets::Environment.new
MyApplication::Application.config.assets.paths.each {|p| environment.append_path p}
rerb = environment['somefile.js.coffee.erb']
rerb.source #=> it's already preprocessed
Or to look into \tmp\cache\assets but there are also only preprocessed files, additionaly obscured by fingerprinted name.
Maybe there is a way to hook into asset-pipeline I have no idea how..
Why I need ERB? To generate client-side-model stubs with fields and validations matching Rails model using KnockoutJS (https://github.com/dnagir/knockout-rails extended -> https://github.com/KrzysztofMadejski/knockout-rails).
I am using Rails '~> 3.2.12', sprockets (2.2.2).
Edit: I've ended up injecting erb code in ### comments, to sneak-peak at generated code while coffeescript file is still compiling:
###
<%= somefun() %>
###
Altough I would suggest using #Semyon Perepelitsa answer as it produces coffee script file as it is seen by coffee compiler.
Just remove "coffee" from the file extension temporarily: somefile.js.erb. You will see its intermediate state at /assets/somefile.js as it won't be processed by CoffeeScript.
I wonder if you can put <% binding.pry %> just before the line and mess around till you get it right. Never tried during a compile and don't use coffeescript. In theory, it should work (or is worth a shot) so long as you put gem pry in your Gemfile and run bundle first.
I need to be using double quotes on my attributes due to a Javascript framework issue I am having, and I have tried setting the Haml::Template.options hash as the documentation recommends when using Rails, however isn't taking affect for the 'assets' folder, regardless of where I am setting the option. Note, it is working on normal ActionView templates being rendered by Rails controllers, but not in templates I have under {Rails.root}/app/assets/javascripts/templates/*.html.haml
This is what I have in {Rails.root}/config/initializers/haml.rb:
Haml::Template.options[:attr_wrapper] = '"'
# Adds the ability to use HAML templates in the asset pipeline for use with
# Batman.js partials
Rails.application.assets.register_mime_type 'text/html', '.html'
Rails.application.assets.register_engine '.haml', Tilt::HamlTemplate
I've also tried changing the register_engine to use Haml::Engine and Haml::Template, which both render, but still don't take my options I set above.
How do I set the Haml options for rendering in the asset pipeline? It seems like I need to pass in options for the Sprocket engine?
I found the solution here.
It's all about monkey patching.
I prefer this variation, as it keeps the options already set for Haml::Template.
Put this at the end of your haml initializer.
class Tilt::HamlTemplate
def prepare
options = #options.merge(:filename => eval_file, :line => line)
# Use same options as Haml::Template
options = options.merge Haml::Template.options
#engine = ::Haml::Engine.new(data, options)
end
end
Because handlebars tags are evaluated after haml is compiled to html, and handlebars counts as plane text in haml you cannot indent logic
{{#if misc}}
%b Misc Products
Total:
{{misc_total}}
{{#each misc}}
{{price_charged}}
{{notes}}
{{/each}}
{{/if}}
Which is hard to read.
I made a rails helper to make this better looking*.
def handlebars_helper(helper, &block)
raise ArgumentError, "Missing block" unless block_given?
open = ActiveSupport::SafeBuffer.new("{{##{helper}}}") # helper opening
open.safe_concat capture(&block)
open.safe_concat("{{/#{helper.split.first}}}") # helper closing
concat(open)
end
which lets you write haml that looks like this
- handlebars_helper 'if misc' do
%b Misc Products
Total:
{{misc_total}}
- handlebars_helper 'each misc' do
{{price_charged}}
{{notes}}
Has this been done before, or is there a better way for me to do it?
*this helper looks a bit messy, I'm not that comfortable with blocks how would I clean this up?
If you want to use HAML to generate handlebars code, you can use hamlbars, which will provide you a few helpers to help facilitate indentation. Unfortunately you'll still be stuck with awkward indentation surrounding if/else.
I'd recommend Emblem.js as an alternative... the syntax is closer to Slim than HAML, but there's gonna be no ugly helper code polluting your templates just to preserve indentation. Disclaimer: I wrote emblem.
If you use haml as rails view template, you can write portion of your page using markdown by using the ":markdown" filter.
Is is possible to do the same using erb?
It's pretty easy to write a method that does it, assuming you're using something like Rails which has #capture, #concat, and #markdown helpers. Here's an example, using Maruku:
def markdown_filter(&block)
concat(markdown(capture(&block)))
end
Then you can use this as so:
<% markdown_filter do %>
# Title
This is a *paragraph*.
This is **another paragraph**.
<% end %>
There are a few things to note here. First, it's important that all the text in the block have no indentation; you could get around this by figuring out the common indentation of the lines and removing it, but I didn't do that in the example helper above. Second, it uses Rails' #markdown helper, which could easily be implemented in other frameworks as so (replacing Maruku with your Markdown processor of choice):
def markdown(text)
Maruku.new(text).to_html
end
Rails 3 has removed the #markdown helper, so just add the above code in the appropriate helper, substituting the Markdown processor of your choice.
ERB does not have filtering like this built-in. You'll need to directly use a gem that handles it, like RDiscount or the venerable BlueCloth.