In a rails app I have an object defined in a controller containing an icon and some values:
#data = "<i class='fa fa-circle fa-lg'></i><span>Speed: </span> #{b.speed.to_f} | Time: #{b.gps_date.try(:strftime, '%-m/%e %H:%M')}} <br />".html_safe.to_json
In view I parse it like this:
<script>
var data = JSON.parse('<%= raw #data.as_json %>');
</script>
But I get the following error:
Uncaught SyntaxError: missing ) after argument list
I works fine when I remove the icon code that contains the single quotes for class
<i class='fa fa-circle fa-lg'></i>
How can I fix this error?
You want to send the HTML string to JS so need of to_json, as this is used to convert Hash to JSON . So just use html_safe in server side.
And in client side, since you have the all HTML in string no need of as_json, just use the string as you would normally do in JS. as_json is a method used as ActiveRecord Serializer.
#data = "<i class='fa fa-circle fa-lg'></i><span>Speed: </span> #{b.speed.to_f} | Time: #{b.gps_date.try(:strftime, '%-m/%e %H:%M')}} <br />".html_safe
and
var data = <%= raw #data %>;
Basically this seems to be an issue with an unescaped ' popping up somewhere in JSON.parse('...'). You can verify the issue by looking at the HTML of the rendered page.
I think you might fix your issue by declaring (no need for the .to_json here):
#data = "<i class='fa fa-circle fa-lg'></i><span>Speed: </span> #{b.speed.to_f} | Time: #{b.gps_date.try(:strftime, '%-m/%e %H:%M')}} <br />".html_safe
And then in the view use
var data = "<%= escape_javascript #data %>";
as you are only tring to pass a string there is no need for the conversion into a JSON object and then parsing it back. (You'd need that if you wanted to pass a whole Javescript Object/Ruby Hash).
Actually for the last line there is also an equivalent shortcut/alias:
var data = "<%= j #data %>";
PS: I described how to fix the imminent issue but generally the point of MVC is to not have (or at least to minimize) presentation logic in a conroller. Generally it would be preferable to pass the data to the view and generate the HTML in the template.
Related
Action: a javascript action attempting to retrieve data based on two parameters, a user-input one and an issuing page parameter.
whereas in the past something like the following would work:
<%= javascript_tag do %> chart.data = data_<%=j params[:nation_id] %>; <% end %>
now with the javascript being 'packed', the compilation of syntax like <%=j params[:nation_id] %> does not work and returns :
/search.json?nation_id=%22%3C%=j%20params[:nation_id]%20%%3E%22&q=mi
modifying the packs/muni.js file as follows, also does not generate a proper url for the search function
var options = {
url: function(phrase) {
return '/search.json?nation_id="#{params[:nation_id]}"&q=' + phrase;
},
getValue: "name",
};
returning
/search.json?nation_id=%22
the page is set with /new?top%5Bnation_id%5D=1&commit=Set
How does the javascript pack need to be written?
Javascript pack is not rendered for each request/visitor - whole point is that it is packed once per deploy and is the same for all (except for when you have several packs, dynamic module loading and other advanced techniques, but still code is not changed per request). In fact, older method with asset pipeline is very similar in this aspect.
Do not try using ruby inside the pack, but instead think of a way to pass the parameter to the js code.
For example, you can pass it via a adding some html tag an querying it from javascript:
In view:
<meta name="nation_id" content="<%= params[:nation_id] %>" />
in js:
nation_id = document.querySelector('meta[name="nation_id"]').content;
return `/search.json?nation_id=${nation_id}&q=${phrase}`;
PS. also you might need to escape your phrase with encodeURIComponent
I have some values on my controller that I want to pass to a javascript function in the view page.
In the controller, I have:
$f3->set('value', $value);
I can access the value on the view with {{#value}}, but how do I use(access) that value inside a javascript function on the view page??
<script type="text/javascript">
var value = XXX; //XXX in the {{#value}}, how do i access it in here???
</script>
It depends on the content stored inside $value.
If it's a basic string with no single/double quote inside, then the following code will work:
<script>
var value='{{ #value }}';
</script>
If it's an integer, the following code will work:
<script>
var value={{ #value }};
</script>
... although your IDE will probably report a syntax error.
If it's a float, the following code will work:
<script>
var value={{ str_replace(',', '.', #value) }};
</script>
... and your IDE will also probably report a syntax error. NB: the str_replace is for non-English locales that have decimal separator set to comma.
For all the rest (strings including quotes or arrays), you should convert your data to JSON, using one of the following techniques:
Technique 1:
Convert data to JSON and dump it to a JS object.
// controller.php (JSON encode)
$f3->set('data',json_encode($data));
<!-- template.html -->
<script>
var data={{ #data | raw }};
</script>
Pros: easy to use.
Cons: your IDE will report a syntax error + extra call to raw.
Technique 2:
Convert data to JSON, dump it to a JS string and parse it.
// controller.php (JSON encode + escape double quotes)
$f3->set('data',str_replace('\\u0022','\\\\u0022',
json_encode($data,JSON_HEX_APOS|JSON_HEX_QUOT)));
<!-- template.html -->
<script>
var data=JSON.parse('{{ #data | raw }}');
</script>
Cons: less easy to use + extra call to raw.
Pros: your IDE will not report any syntax error.
Technique 2bis:
Embed technique 2 in a F3 template filter.
// index.php
$tpl=Template::instance();
$tpl->filter('safejson',function($data){
$raw=\View::instance()->raw($data);
return str_replace('\\u0022','\\\\u0022',
json_encode($raw,JSON_HEX_APOS|JSON_HEX_QUOT));
});
<!-- template.html -->
<script>
var data=JSON.parse('{{ #data | safejson }}');
</script>
Pros: easy to use + your IDE will not report any syntax error.
Cons: extra call to raw.
Technique 3:
Convert data to JSON and embed it inside a DOM data- attribute.
// controller.php (JSON encode)
$f3->set('data',json_encode($data));
<!-- template.html -->
<div id="foo" data-json="{{ #data }}"></div>
<script>
var data=JSON.parse(document.getElementById('foo').dataset.json);
</script>
Pros: easy to use + your IDE will not report any syntax error + no extra call to raw.
I went a bit lazier than that.
I have my data in a dictionary file (F3). I load it in an input field at the bottom of my page and assign value via templating. I use Jquery (plain JS could be used to) to retrieve value.
Ex:
Dict data
'prf_conf'=>' Update your profile'
In my profile.html
`< input type = 'hidden' id ='prf_conf' value='{{#prf_conf}}' >`
//this loads data in whatever language on my page
JS
Confirm button text: (i used jquery-confirm.min.js in this example)
$.confirm({ title: $('#prf_conf').value()
… bit of gymnastic but worked well. No IDE issue…
I’m using Rails 4.2.3. In my view, I want to output some JS, so I have this
<%
puts "size: #{#user_my_objects.size}"
js_data = []
#user_my_objects.each do |user_my_object|
my_object_day_fmted = user_my_object.my_object.day.strftime("%Y/%m/%d")
js_data.push( "[new Date('#{my_object_day_fmted}')).getTime(), #{user_my_object.time_in_ms}]" )
end
%>
var data = [<%= js_data.join(",") %>];
but Rails keeps converting my apostrophes to “'” characters and its causing “Uncaught SyntaxError: Unexpected token &” JS errors when the page renders. Here is an example of how the output looks
var data = [[new Date('2011/10/23')).getTime(), 1286000],[new Date('2013/08/11')).getTime(), 2779000],[new Date('2013/10/26')).getTime(), 1288000],[new Date('2014/06/28')).getTime(), 2915000],[new Date('2014/09/07')).getTime(), 6256000],[new Date('2015/07/25')).getTime(), 2788000],[new Date('2015/08/22')).getTime(), 1488000]];
How do I prevent Rails from applying HTML escaping to characters for this page only?
try this one instead
<%= raw %>
I've created a rails action that makes a GET request to a service and then passes the response to the view as #job_data. The code works fine in retrieving the response, and I've verified the json object looks correct.
def show
#url = URI.parse(##jobs_base_url + "/" + params[:id] + "?TestMode=true")
req = Net::HTTP::Get.new(#url.to_s)
res = Net::HTTP.start(#url.host, #url.port) {|http|
http.request(req)
}
#job_data = HTMLEntities.new.decode res.body
end
However, I'm trying to do a little javascript to manipulate DOM elements using this json object. I'm trying to insert the script into the html to do something very basic with the json object, but can't seem to get it to pass correctly:
<script type="text/javascript" charset="utf-8">
$(function() {
var $data = <%= #job_data %>;
$('#jobtable').append($data.Id);
When I debug the page I see that all the entities in the string are encoded (e.g. " instead of quotation marks). I've tried to de-entityify the string with HTMLEntities as in the code above for the action, but it has no effect and is the same as if I had left the #job_data set to:
#job_data = res.body
Can anyone explain where the encoding happens and how I can resolve this? Is the problem with the action or with the javascript in the view? What's the preferred way to pass a json string/object from a response in an action to javascript in the view?
Already answered here:
Ruby json gem is encoding html entities
The trick is to use raw in the view's embedded ruby to avoid the encoding:
var $data = <%= raw #job_data %>;
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) %>