Rails: When Escape Javascript - ruby-on-rails

My question is if ruby code inside script tag MUST be always escaped?
Have I to escape javascript when I set a class/id of a div for example?
<script>
$("#button_<%= comment.id %>").click(function(){
... ...
... ...
});
</script>
OR
<script>
$("#button_<%= escape_javascript comment.id.to_s %>").click(function(){
... ...
... ...
});
</script>
Or ruby code must be escaped only when render partials? Thank you

Related

Rails wait for Turbolinks to be loaded to execute JavaScript import

Ich want to call a JavaScript function within the application.html.erb. The function is imported and provided in the application.js:
import myFunction from 'myJSModule';
window.myFunction = myFunction;
I am using turbolinks and vite_rails and it seems like the JS function is called before the application.js is loaded and it is undefined.
Example:
application.html.erb
<html>
<head>
<script type="text/javascript">
</script>
<%= vite_javascript_tag "application", 'data-turbolinks-track': "reload" %>
<%= render "layouts/partial" %> # here I call the window.myFunction
</head>
<body></body>
</html>
layouts/_partial.html.erb
<script>
window.myFunction
</script>
Behaviour:
window.myFunction is undefined.
When I try to call the function in the console, after the side is loaded, then it is defined.
Also when I wait for the turbolinks:load event:
document.addEventListener("turbolinks:load", function() { window.myFunction }
The Problem with the event is, that it is triggered every navigation event, but I want to call the function only when the partial is re-rendered.
I recently migrated from webpack to vite. For webpack the solution seemed to be to move the render partial below the java_script_tag. Unfortunately, this does not work with with vite.
I could find a solution. Appending the attribute type of the script with module:
<script type="module">
window.myFunction
</script>

Need to pass parameter from partial render to a javascript function in .html.erb file?

I will post only the relevant snippet of the file
index.html.erb
<%= render "trace/outbound_message", error => #msg_error,:selector => "#ui-accordion-accordion-panel-3", :tab => "ui-id-1" %>
_outbound_message.html.erb
<% unless error.blank? %>
<%= error.html_safe %>
<script>
$(function() {
show_error(<% selector %>,<% tab %>);
});
</script>
<%end%>
But this function is not able to be called successfully, as I don't think js undersands the embedded ruby code. What is my quickest workaround? Do I have to call a js.erb file, and how do I pass parameters to & in it?
UPDATE
I changed the script to
<script>
alert("check-up");
$(function() {
show_error(<%= selector %>,<%= tab %>);
});
</script>
And even that alert is not being shown? Any ideas?
Use the ruby code in a block like:
In Ruby code:
v = "show_error(<%= selector %>,<%= tab %>);"
In javascript:
<script>
$(function() {
$(#{v});
});
</script>
I think the problem is you quotes ! You should have something like this
show_error(foo,bar);
and you need something like
show_error('foo','bar');
And don't forget to escape your JS :
show_error('<%= escape_javascript(#selector) %>', '<%= escape_javascript(#tab) %>');
How about this ?
<script>
alert("check-up");
$(function() {
show_error(<%= selector.to_json %>,<%= tab.to_json %>);
});
</script>
The to_json function will wrap your variable between quotes, that were missing.
I was playing around, and I figured it out.
<%= javascript_tag( "$(function() {show_error('#{selector}','#{tab}');});")%>
The javascript_tag played a vital role. You can't enclose it in ...
Btw #Saurabh - You were exceptionally close to the answer, no idea why somebody down-voted you.

Rendering a partial using ajax

It seems simple but my partial is not rendered in a view(dash.html.erb) using ajax.
routes.rb
match "users/dash" => "users#dash"
users controller
def dash
respond_to do |format|
format.js
end
end
dash.html.erb
<div id= "mydiv">This view is not shown using ajax.</div>
dash.js.erb
$('#mydiv').html('<%= raw escape_javascript render("cart_payment") %>');
My partial- _cart_payment.html.erb
<p>This is a partial.</p>
UPDATE:
users/index.html.erb
<script type= "text/javascript">
$.ajax({
url: "users/dash",
data: {
//params if needed
}
});
</script>
Please note that I am calling- users url in browser because ajax is called from here.
Is it not correct way or Am I missing something?
When you call the dash method remotely, it actually is executing the $('#mydiv').html... code. The problem is, your index.html.erb file has no <div id='mydiv'> to update in the first place.
If you replace your index.html.erb with this, it should work:
<div id='mydiv'></div>
<script type= "text/javascript">
$.ajax({
url: "users/dash",
data: {
//params if needed
}
});
</script>

How to safely embed JSON with </script> in HTML document?

In a Rails 3.1 app, how can I safely embed some JSON data into an HTML document?
Suppose I have this in a controller action:
#tags = [
{name:"tag1", color:"green"},
{name:"</script><b>I can do something bad here</b>", color:"red"}
]
And this in a corresponding view:
<script type="text/javascript" charset="utf-8">
//<![CDATA[
var tags_list = <%= #tags.to_json %>;
// ]]>
</script>
Then I get this in resulting HTML:
var tags_list = [
{"name":"tag1","color":"green"},
{"name":"</script><b>I can do something bad here</b>","color":"red"}
];
which triggers a SyntaxError: Unexpected token & in Chrome
If I remove the Rails' default HTML escaping with <%=raw tags.to_json
%>, then it returns this:
var tags_list = [
{"name":"tag1","color":"green"},
{"name":"</script><b>I can do something bad here</b>","color":"red"}
];
which, of course, breaks the HTML document with </script>.
Can I somehow tell to_json() method to return something more like this:
var tags_list = [
{"name":"tag1","color":"green"},
{"name":"</script><b>I can do something bad here</b>","color":"red"}
];
I asked this question on rubyonrails-talk mailing list, and I understand now that some people think that's a very bad idea to begin with, but in my case it works very nicely, as long as there are no HTML special chars in the data. So I just want to make the string returned by to_json HTML safe and still have JavaScript parse it properly.
UPDATE:
Based on #coreyward comment, I did make it a JS string literal, and that seems to be working great now. Its not quite as elegant of a solution as I was hoping for, but its not too bad either. Here is the code that is working for me:
<% tags = [{name:"tag1", color:"green"}, {name:"</script><b>I can \n\ndo something bad here</b>", color:"red"}] %>
<script type="text/javascript" charset="utf-8">
//<![CDATA[
var tags_list = $.parseJSON('<%=j tags.to_json.html_safe %>');
// ]]>
</script>
which results in:
<script type="text/javascript" charset="utf-8">
//<![CDATA[
var tags_list = $.parseJSON('[{\"name\":\"tag1\",\"color\":\"green\"},{\"name\":\"<\/script><b>I can \\n\\ndo something bad here<\/b>\",\"color\":\"red\"}]');
// ]]>
</script>
Your code using just #tags.to_json works in rails3, if you enable it with:
ActiveSupport.escape_html_entities_in_json = true
Otherwise, your other option is this:
var tags_list = <%= raw #tags.to_json.gsub("</", "<\\/") %>;
This saves the client having to parse the whole thing through $
The proper way in 2019 is to wrap obj.to_json with json_escape function. json_escape is directly intended for escaping specific HTML symbols inside JSON strings. Example below from the documentation:
json = JSON.generate({ name: "</script><script>alert('PWNED!!!')</script>"})
# => "{\"name\":\"</script><script>alert('PWNED!!!')</script>\"}"
json_escape(json)
# => "{\"name\":\"\\u003C/script\\u003E\\u003Cscript\\u003Ealert('PWNED!!!')\\u003C/script\\u003E\"}"
JSON.parse(json) == JSON.parse(json_escape(json))
# => true
It seems this page appears on top of Google Search results, that's why I decided to provide a comment with an update :)
btw, this works but is not a good solution in my opinion:
<script type="text/javascript" charset="utf-8">
//<![CDATA[
var tags_list = <%=raw #tags.to_json.gsub('/', '\/') %>;
// ]]>
</script>
I think that if you try this it will work:
var tags_list = "<%== #tags.to_json.gsub('/', '\/') %>";
(Notice the double == and the " ")
For instance with this in app/layouts/application.html.slim:
javascript:
window.translations = #{raw t("js").to_json};
And this in the translations:
js:
name:
must_be_present: Must be present<script>alert(1)</script>
The result will be escaped:
<script>window.translations = {"name":{"must_be_present":"Must be present\u003cscript\u003ealert(1)\u003c/script\u003e"}};</script>

how to access javascript variable in rails view

Is there any way to access javasript variable inside the rails view.
I just set some value of javascript variable and want to access it in rails view.
Thanks
You have to understand that ruby code in your views gets executed on the server - before any javascript on the page gets a change to be executed.
That's why you cannot do stuff like this:
<script>
var js_var = 1;
</script>
<%= get_value_of_js_var_somehow %>
The other way round it works:
<script>
var js_var = <% generate_value_with_ruby %>;
do_something_in_javascript_with_js_var();
</script>
You can pass a javascript variable to rails using AJAX. For example if you want to pass the id for an user to a method in a rails controller from javascript you can execute the following code:
<script>
var id = 1;
<%= remote_function :url => {:controller=>'controller_name', :action=>'method_name'}, :with => "'user_id=' + id" %>
</script>
You will receive the variable through a POST request, as a parameter. You can access it using params[:user_id].
def method_name
if params[:user_id].exists?
u = User.where('id = ?', params[:user_id]).first
end
puts u.path
end
Hope I've answered your question.
If you have this Javascript variable in a higher piece of javascript (per se: the application.js), then you can always just reference it in the view.
#application.js
var someVar = "Hello World";
Then in your view (executed on the client), you could to...
<script type='text/javascript'>
alert(someVar);
</script>
I think we need more specific ellaboration if one of these three posts doesn't answer your question.
Suppose we are having script as follows
<script type="text/javascript">
var a="some value";
document.getElementById('tagid').innerHTML='<%= tag(:div,content_tag(:p,' " +a+ " '), :id=>' " +a+ " ', name=>"somename") %>';
</script>

Resources