How does one minify a javascript partial within a rails erb file? - ruby-on-rails

The application is not using the standard asset pipeline due to having some of the javascript being rendered dynamically by controller variables.
I'd like to minify the js before appending/inline-ing it into the html file that it would be served out from.
I've tried <render :partial => 'javascript.js'> which is the standard way to render a partial in an erb.
Ideally i'd just be able to do <render :partial => Minify.new.minify('javascript.js')> to render out a minified version of the js

You can try the uglifier gem (http://rubygems.org/gems/uglifier), I don't know about the performance, but you can do something like:
<script type="text/javascript">
<%= raw Uglifier.new.compile(render "your_js_in_a_partial.js") %>
<script>

Related

Rendering a partial via coffeescript prints literal

I'm trying to render a partial from coffeescript when a button is clicked, so I have one of my coffeescript files "script.js.coffee" with the following code:
$('[id^="btn_add_rep_dia_"]').click ->
id = this.id.substring(16)
$("#dia" + id).append("<%= j render('repeticions/form') %>")
But what's happenning is that at the end of $("#dia" + id) appears litterally the text "<%= j render('repeticions/form') %>". The partial is located in "repeticions" folder and it's called "_form.html.haml"
I have also tested the last code line as:
$("#dia" + id).append("<%= escape_javascript( render partial: 'repeticions/form') %>")
You are trying to execute an erb (embedded ruby) template inside a .coffee file. Rails doesn't know that it should pre-process the file before sending it to the client.
If you are using a Rails version > 3.2, then simply renaming your coffeescript file from script.js.coffee to script.js.coffee.erb should be enough to instruct rails to interpret the erb style template strings (<%...%>).
You can't render a partial from a plain coffeescript file. If you wanted to do this approach, I suggest turning that button into a link_to with remote: true which will enable you to use ajax in rails.

Access asset_host inside javascript for Rails?

I have the following javascript (shortened for clarity):
$modal = $('<img src="/assets/loading.gif">');
$('body').append($modal);
But I am not sure how to access the asset_host within that javascript? Any suggestions? (I am trying to not use coffee script)
There are several options:
asset_path
If you're not accessing the file inside the asset pipeline (and consequently can use ERB code), you could use this:
$img = '<%=j image_tag asset_path("loading.gif)" %>'
$('body').append($img);
Gon
If you are accessing inside the asset pipeline (where you can only use pure JS), you'll have to pass the asset host variable to JS through HTML. Gon is a great way to do this:
#config/initializers/gon.rb
gon.push({asset_host: ActionController::Base.asset_host})
#app/views/layouts/application.html.erb
<%= include_gon %>
#app/assets/javascripts/application.js
$modal = $('<img src="' + gon.asset_host + '/assets/loading.gif">');
$('body').append($modal);
Got the asset_host reference from here

Rails 3. Not able to pass locals in a Partial js file with locals

I have a lot of js files like new.js, index.js, create.js etc that handles my Ajax calls and other jquery code
As the have many common code snippets I have tried to use partial js files
For example I have a new.js file that calls a partial _new.js
new.js
<%= render :partial=>'new', :formats=>[:js],:handlers=>[:erb] %>
_new.js
<% if params[:group_id]%>
$("#group_participants_content").html("<%= escape_javascript(render(:partial=>'form'))%>");
$(".remote_selected").removeClass("selected remote_selected simple-navigation-active-leaf");
$("#group_mail").addClass(" remote_selected simple-navigation-active-leaf");
<%else%>
$("#users_content").html("<%= escape_javascript(render(:partial=>'form'))%>");
$(".remote_selected").removeClass("selected remote_selected simple-navigation-active-leaf")
$("#mail").addClass("remote_selected simple-navigation-active-leaf");
<%end%>
// Change our States
History.replaceState({action:'<%= "#{controller.action_name}/#{controller_name}" %>'}, '<%= "#{controller.action_name.titleize} #{controller_name}" %>', '?action=<%= "#{controller.action_name}/#{controller_name}" %>');
var url=History.getState().url;
$("#help").attr('href',"/helps/0?url="+url)
That works but to be useful I would like to add locals as
<%= render :partial=>'new', :formats=>[:js],:handlers=>[:erb], :locals=> {:id=>"#group_participants_content"}%>
and change _new.js to
$('"'+id+'"').html("<%= escape_javascript(render(:partial=>'form'))%>");
However that does not work- The js file seems then not to be loaded at all
Anyone that has any suggestion of what is wrong ?
Appreciate any help ?
It's
$("<%=id%>").html("<%= escape_javascript(render(:partial=>'form'))%>");
The id coming is already in quotation, your code will wrap it again in quotation, pass it directly.Hope I should work:
$(id).html("<%= escape_javascript(render(:partial=>'form'))%>");

how should I include a coffeescript file on only one page?

Edit: a year later if I was going to do this again I'd do it with curl.js instead of Rails asset pipeline.
Related: Best way to add page specific javascript in a Rails 3 app?
I'm writing an app and using coffeescript to generate all of the js. That's why the related question doesn't do what I need.
I'd like to be able to put a coffeescript file in a subfolder of my assets directory and have that .coffee file only get served up on one page. The page is on a named route
match 'myNotifications' => 'user#notifications'
The most obvious thing to do was to put the .coffee file in assets\javascripts\user\index.js.coffee. But after reading the docs about assets I'm unclear.
I read this line (from http://guides.rubyonrails.org/asset_pipeline.html):
You should put any JavaScript or CSS unique to a controller inside
their respective asset files, as these files can then be loaded just
for these controllers with lines such as <%= javascript_include_tag
params[:controller] %> or <%= stylesheet_link_tag params[:controller]
%>.
Ok cool, so I put the page specific js in assets\javascripts\user.js.coffee. Then I reloaded my home page, Ctrl F5. The user.js file is still being loaded on the homepage. Tested with $ -> alert 'ready from users controller'; seeing that alert when I load the homepage.
Does Rails have a way to have a per-page coffeescript file that will only be served up with that page? Am I reading the manual wrong? Is there a place in the assets folder that I can put .coffee files where they won't get loaded with every page?
Update: Looks like I might have an answer:
There are a couple of ways that we can get around this problem. We
could use require_directory instead of require_tree as this will only
load the files in the current directory and not in subdirectories. If
we want more control over the included files we can require them
separately instead of including the whole directory. Alternatively we
could move the JavaScript files that we want to be included on all
pages into a public subdirectory. We can then use require_tree
./public to include just those files.
I'll give that a shot in the AM.
Here's the approach I use to make controller/view specific Coffee:
application.html.haml:
%body{ :data => { :controller => params[:controller], :action => params[:action]} }
alt. application.html.erb
<%= content_tag(:body, :data => { :controller => params[:controller], :action => params[:action] }) do %>
...
<% end %>
application.js.coffee:
$(document).ready ->
load_javascript($("body").data('controller'),$("body").data('action'))
load_javascript = (controller,action) ->
$.event.trigger "#{controller}.load"
$.event.trigger "#{action}_#{controller}.load"
users.js.coffee
$(document).bind 'edit_users.load', (e,obj) =>
# fire on edit users controller action
$(document).bind 'show_users.load', (e,obj) =>
# fire on show users controller action
$(document).bind 'users.load', (e,obj) =>
# fire on all users controller actions
Sidenote:
This works great with PJAX as well as you can pass the controller/action names with the response header on PJAX requests and just fire these js functions based on that.
EDIT (2014/03/04):
This solution still works when using turbolinks.js.
Rather than only including the file on one page, you might want to just use logic that's conditional on the page markup. See my answer to a related question. That way, your users don't have to make an additional <script> request for the particular page.
If there's a lot of logic specific to that page (say, 10K+ minified), then yes, split it out. As you suggested in the edit to your question: Rather than doing require_tree . at the root of your javascripts directory, instead create a sub-directory called global and change the top of application.js from
require_tree .
to
require_tree global
Then put your page-specific CoffeeScript file in the root javascripts directory, and point to it with a javascript_include_tag call in that page's template.
include javascript tag into your view template, like show.html.haml
- content_for :javascripts do
= javascript_include_tag 'folder/coffee_file_name'

Embedding an ejs template inside of an erb template

I'm building a javascript-heavy rails 3 app. It uses underscore.js, which has a very elegant templating mechanism built on top of ejs ( http://embeddedjs.com/).
The problem: embeddedjs borrows heavily from the erb syntax, so including ejs templates in an erb template causes rendering problems with the view.
Is there a way to include "non-erb" sections in an erb file? This would let me define ejs templates inside erb files. Right now I'm using a hack where I have a helper that reads the raw contents of a file containing ejs templates, and outputting that as a raw string in the erb template.
I use this trick to solve the problem:
// Using custom tags to be able to use regular for templates in templates
var ejs = require('ejs');
ejs.open = '{{';
ejs.close = '}}';
// Using html extension for custom ejs tags
app.register('.html', ejs);
app.set('views', __dirname + '/views');
app.set('view engine', 'html');
This changes <% %> to {{ }}, and let me use <% %> for templates which are used by JS. This works for me as I don't have classic style templates (<% %>).
If you have a lot of those you may want to do the same trick but for underscore.js templates.
You could save ejs as a seperate file and than render it as a text (which won't be evaluated as erb) inside script tag.
Inside your erb partial:
<script id="my_awesome_template" type="text/x-ejs">
<%= render :text => File.open("app/views/controller_name/_my_awesome_template.html.ejs").read %>
</script>`
In your JavaScript file:
new EJS({element: document.getElementById('my_awesome_template')}).render(data)
Escape your Underscore variables: (The ones you do not want erb to interpolate)
<%= foo %> becomes:
<%%= foo %>

Resources