Share rails templates front and back with JST support - ruby-on-rails

I would like to share js templates between front and back in a rails application for cases where the code would be duplicated.
The requirements are:
Either underscore (ejs) or handlebars/mustache templates. Preferably ejs because I'm already using underscore client side.
I'd also like to utilize the rails asset pipeline to pull these into JST object/functions so I can keep the template files separate and can get the other benefits like cacheing etc.
I've found some gems that work for one case or the other like handlebars_haml_assets, ejs, FlavourSaver etc but none that allow for all of these requirements out of the box. What is the best way to share js templates front and back and also use JST in a rails 3 app?

Rails 3.2 asset pipeline, out-of-the-box, supports Embedded Javascript (EJS) or Embedded CoffeeScript (Eco) templates and are made available using a JST (JavaScript templates) namespace. Just name your files appropriately:
app/assets/templates/top_level.jst.ejs
app/assets/templates/subdir/nested.jst.eco
To use them in your javascript:
var html = JST['top_level']({ data: 'something' });
var html = JST['subdir/nested']({ data: 'something' });

Related

Where to store angular templates in Rails?

I'm using angular.js as my clientside framework and rails as my serverside framework. One slight stumbling block is where should I store my angular view templates?
Let's say I'm making a custom directive:
directive("foobaz", function (cart) { return {
restrict: "E",
templateUrl: "components/bing/foobaz.html"
}
How should I serve up components/bing/foobaz.html? Should I put it in my public folder:
root/public/bing/foobaz.html
Or should I make routes and a controller to serve up angular views?
Make a folder app/assets/templates/.
It will hold all of your angular templates. please refer this link to get more details http://start.jcolemorrison.com/setting-up-an-angularjs-and-rails-4-1-project/
you can use layouts folder in
app -> views -> layouts
or
with .yml, we can store it in config and no need to mention in routes.
We have angular-rails application.
And we store templates in app/assets/templates dir, and use haml for templates. For those purposes we're using angular-rails-templates gem

Use Rails Sprockets directives when rendering js from controller

I want, from a controller, to render a .js.coffee view that includes another js file from the lib/assets/javascripts directory:
#= require doc_ready
Why a view rendered by a controller instead of a static asset?
Because I want to refer to the file through an absolute url, that doesn't changes. Rails 4.0 only compiles assets with a digest like embed-dc589fbef3832d9c38a4fbbc4b021f59.js and I want to use the same url (and possibly expire the cache file based on time), even if I make changes to the script.
Why an absolute url?
Because I want to use the script externally on another website, and the code I give to the webmaster of that site mustn't change.
Why do I want to include another js from the assets?
To keep the code DRY
To require a simple library that simulates the jquery ready event, used to create widgets on the page that included the script.
Can I achieve that by making a controller action that renders a .js.coffee view, which compiles and includes other needed js files from the library, just like sprocket does when compiling assets?
Use redirection like so:
def show
redirect_to view_context.javascript_path('embed.js.coffee')
end
There is a way to render whole js file:
def show
render text: Rails.application.assets.find_asset('embed.js.coffee').body
end
I managed to find a way to do it, by using this answer.
The controller is left untouched:
class Widgets::EmbedJsController < ActionController::Base
def embedded_script
end
end
In the coffeescript view, I have "required" the other file like this:
`<%= raw Rails.application.assets['doc_ready'].body %>`
Seems to work locally, I'll test in production soon.
This can also be refactored by just serving Rails.application.assets['widgets/embed'].body directly from the controller, which should compile coffeescript but have not tested it.
Another approach is to symlink or copy the digest version of the asset to some constant path (and give that to the 3rd party). This has the advantage that the requests shouldn't hit rails at all (since these should be served directly by the web server.
It is relatively simple to automate this - two libraries that I am aware of that do this are
non stupid assets
asset_symlink (I wrote this one)

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.

loading scripts in a defined order in rails app. how to?

I noticed that some jquery effects requires that scripts are loaded in proper order.. in my case it is working if they are loaded like this:
jquery 1.4.4
jquery-ui-1.8.16.custom.min.js
autocomplete-rails.js
jquery.cycle.all.js
....
if they load in different way then some of my animation or jquery feature is not working. So how do I specify in rails wich script to load first?
Right now I did it in a primitive way by adding 1 2 3 numbers in front of names of every script I have in order that I need resulting in:
1jquery 1.4.4
2jquery-ui-1.8.16.custom.min.js
3autocomplete-rails.js
4jquery.cycle.all.js
It's primitive but it's working. Is there another way of doing it?
Rails 3
For Rails 3.0:
javascript_include_tag takes an array of sources, and includes them in the order that you define. You can omit :defaults, or define it in your application.rb file with config.action_view.javascript_expansions[:defaults] = %w(foo.js bar.js). :all includes all the javascripts in your /javascripts/ folder.
Therefore, it's best to have jQuery at the beginning, since most or all of your javascript files will use jQuery.
More documentation: http://apidock.com/rails/ActionView/Helpers/AssetTagHelper/JavascriptTagHelpers/javascript_include_tag

How can I access Rails objects in Sass?

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).

Resources