How to render html.erb file to assets/javascript? - javascript

Below is the code I have in my assets/javascripts/investment.js file:
investment_updates.forEach(function(investment_update, n){
data.push(new Item((n+1)*space, (n+1)*space, (n)*angle));
add(n+1, "<%= render '/investment_updates/single_investment_update', investment_update: investment_update %>")
});
I want to render views/investment_updates/_single_investment_update.html.erb file in my javascript file and I tried below code but didn't work.
<%= render '/investment_updates/single_investment_update', investment_update: investment_update %>
Help me to render partial in my js file as a parameter.

Your js file should end in .js.erb instead, so it will be picked up by the Rails Asset Pipeline.
Note though that the way you are inserting data in a string is quite brittle. One misplaced ' or " can break your Javascript

Related

Rails - Move view's javascript code to javascript files

First let me tell you that I've searched for this and didn't manage to find any answer for my problem.
I have a lot of Javascript on my layouts/application.html.haml file:
### at the end of application.html.haml file
- if #instance_variable.condition
:javascript
// a lot js/jQuery code
:javascript
// more js code that uses #{ #instance.vars }
- if #another_condition.using.ruby.cody
:javascript
// more js code that uses #{ #instance.vars }
And I'm using instance vars within this code, which means that this vars will only be declared on the controller (application controller). As this is the application layout, these scripts run on every page of my website (and that's what I need of course).
What I want is to move all this code to a js.erb file (or .haml if possible). First - because is easier to manage this code in a separate file; Second - because I don't want to have <script> // a lot of js code </script> tags at the end of every html file, I want to have a <script async src='link'/> tag only.
Also I'm including already the application.coffee at the beginning of the file, but I need this script tag at the end of the html files.
I wouldn't recommend using partials for this. Because, your code uses variables, this means it changes depending on your variables. If you put them into a separate javascript file, the browser wouldn't know about the changes and use a cached file. A workaround would be to add some string (that changes when vars change) at the end of your filename, but then, you would lose all the benefits of moving your javascript into separate files.
A better way would be to define variables in your application.html.haml, move out your javascript code into separate files and just use defined variables.
application.html.haml
- if #instance_variable.condition
%script(src="path/to/my/script.js")
:javascript
= var some_var = #{#instance.vars}
%script(src="path/to/my/second_script_that_uses_var.js")
Thank you for your answer Uzbekjon, but after some research I found a way to do exactly what I wanted :)
In my 'layouts/application.html.haml' file, I added a script tag:
### at the end of application.html.haml file
%script{async: 'async', src: application_scripts_path}
Then I added this path to routes:
get 'application_scripts' => 'controller#application_scripts', as: :application_scripts
Then I just had to set this action application_scriptson my controller and create a new view (app/views/controller/application_scrips.js.erb):
class Controller < ActionController::Base
# 1
protect_from_forgery except: :application_scripts
def application_scripts
# 2
if condition.that.tells.me.this.request.is.valid
# 3
render formats: [:js] and return
end
render plain: ''
end
These steps were of course the harder ones to find out:
1 - I had to disable this protection, or else I would get this error:
ActionController::InvalidCrossOriginRequest at /application_scripts
Security warning: an embedded tag on another site requested protected JavaScript. If you know what you're doing, go ahead and disable forgery protection on this action to permit cross-origin JavaScript embedding.
2 - To make sure that no other site can request this script file (not that it could be a problem for me, but I preferred this way) I added a condition that makes sure the request comes from my website. In this case I was just checking if a user as logged in.
3 - The formats: [:js] tells Rails that the view is not .html, instead it's a .js file 'application_scripts.js.erb'
Finally I just had to move all my code from the application.html.haml file to the view file 'application_scripts.js.erb' and convert from haml code to erb as well.
<% #instance_variable.condition %>
// a lot js/jQuery code
// more js code that uses <%= #instance.vars %>
<% #another_condition.using.ruby.cody %>
// more js code that uses <%= #instance.vars %>
<% end %>
<% end %>

outputing ruby strings in js.erb file

I am making some ajax call and in my js.erb file I put
$("body").append(<%= escape_javascript(render("layouts/some_layout")) %>);
I had no output in my html file, but in my log, render("layouts/some_layout") is correctly called. So for debugging purpose, I put
$("body").append(<%= j "<div>test</div>" %>);
But this also output nothin. Why is it so ?
I guess you should have your erb code enveloped with quotation marks, otherwise you'll probably get JS syntax error:
$("body").append('<%= escape_javascript(render("layouts/some_layout")) %>');

Render ERB with underscore templates without displaying in browser

Am trying to generate a PDF from a HTML file which itself is generated from dynamic content. So there is a controller action "generate_pdf" which takes HTML content and renders a PDF. The pdf generation bit works fine. Generating the HTML is where I am stuck.
#reports_controller.rb
def generate_pdf
#report = Report.where(:id => params[:id])
html_content = render_to_string(:layout => false)
#Use the html_content to generate PDF
end
Now the erb file is as follows :
#views/reports/generate_pdf.html.erb
This is the generated pdf from erb.
The following is a generated content. The report's id is <%= #report.id %>
and the name is "<%= #report.name %>". </br>
It has <%= #report.items %> items.
This erb without any underscore templates works great and render_to_string generates correct HTML content.
But now if I use underscore.js templates ( the same report is also displayed in browser and the application uses Backbone.js and Underscore.js a lot) to generate the content of the report then render_to_string returns incorrect HTML. By incorrect, I mean, the output is the underscore.js template code itself and not the actual content.
{{ _.each(items, function(item) { }}
...
There is no JavaScript environment available inside render_to_string that would render the underscore.js templates. How can I handle this situation? Since most of our templates are in underscore.js, we thought it would make sense to reuse as much as of it as possible instead of creating a different template (in ERB ) just for PDF.

How to deal with HTML entities in Rails to_json output?

I'm writing an app that uses Rails on the backend and javascript/backbone on the frontend. I'm trying to bootstrap some rails models into my javascript. Specifically, I'd like to load the contents of #courses into a js variable called window.courses. I've got the following in an html.erb file.
<%= javascript_tag do %>
window.courses = JSON.parse('<%= #courses.to_json %>');
<% end %>
I'm expecting the erb preprocessor to render this into valid javascript, like so
<script type="text/javascript">
//<![CDATA[
window.courses = JSON.parse('[{"code":"myCourseCode", ...
//]]>
</script>
... but, instead, I'm getting code that includes HTML entities.
<script type="text/javascript">
//<![CDATA[
window.courses = JSON.parse('[{"code":"myCourseCode", ...
//]]>
</script>
Obviously, I get javascript errors when I try to parse this.
Does anyone know how I can deal with these HTML entities in order to produce valid javascript? I realize that one option would be to unescape the entities on the client side, but this seems like a roundabout solution. Is there a way that I can get Rails to produce JSON that doesn't need unescaping?
If you intend to use raw(obj.to_json) you MUST ensure the following is set.
ActiveSupport.escape_html_entities_in_json = true
The question is solved by my comment, just for the record:
Rails escapes strings that are printed using <%= 'string' %>. By this, it is save to ouput user data.
So, if you don't want Rails to escape the output, you have to tell Rails explicitly by using raw('string').
In your code, that would be:
<%= raw(#courses.to_json) %>

Access Rails global constant in Javascript / jQuery

My setup: Rails 3.0.9, Ruby 1.9.2, jQuery 1.6.2
Rails
constants.rb (initializer file)
DEFAULT_REPLY = "Add a reply..."
Rails
index.html.erb
<%= javascript_include_tag 'reply' %>
...(rest of view code)...
reply.js
$(function() {
var default_reply = <%= h DEFAULT_REPLY -%>;
...(rest of jQuery code)...
});
This throws an error Uncaught SyntaxError:Unexpected token %=, I tried to enclose it in quotes like var default_reply = '<%= h DEFAULT_REPLY -%>' and it output the value as is, meaning default_value has the value of <%= h DEFAULT_REPLY -%>' which is clearly not what I intended. What am I doing wrong?
EDIT
Given the feedback, I have reconsidered and is now using a local variable and jQuery to pull the value from the textarea upon page load.
You need to add .erb to the end of your .js file, along with add the quotes around the string.
The name of your javascript file should be reply.js.erb.
Currently, your .js file is not being run through rails, and is being served statically. That is why when you put the quotes around the string, it output the string '<%= h DEFAULT_REPLY %>' instead of the correct text.
I'd strongly recommend against this approach but I think you're confusing two things here.
Assuming reply.js is in public/javascripts/reply.js, this is a static JS file that is served up by your server. You cannot put any dynamic ("server side") code in here as the file is not evaluated in any manner, just passed back statically.
If you want a global JS variable to use in your files, you'd need to do assign it in your layout file app/views/layouts/application.html.erb or in your action files (index.html.erb, show.html.erb, etc).
Any ERB file is evaluated before returning it, so you could put
<script type='text/javascript'>
$(function() {
var default_reply = "<%= escape_javascript DEFAULT_REPLY %>";
});
</script>
above the <%= yield %> statement of your layout file.
Again, I'd STRONGLY recommend against this approach but if that's why you need, I think this will solve it.
It sounds like you named your view template incorrectly, does it end in .html.erb? If not, it won't evaluate the ERB fragment you pasted.
Once you fix that, you can embed what you want with the following ERB code:
$(function() {
var default_reply = "<%= h DEFAULT_REPLY -%>";
...
});
If it is a rails 3 App why are you using that syntax? try:
var default_reply = <%= DEFAULT_REPLY %>;

Categories