How to implement a 'safe' periodical executer without using the Rails helpers? - javascript

I am very new to Ruby on Rails and was never really big on writing JavaScript, so the built in helpers were like a tiny silce of heaven.
However I have recently learned that using the helper methods creates "obtrusive javascript" so I am doing a tiny bit of refactoring to get all this messy code out of my view. I'm also using the Prototype API to figure out what all these functions do.
Right now, I have:
<%= periodically_call_remote(:url => {:action => "tablerefresh", :id => 1 }, :frequency => '5', :complete => "load('26', 'table1', request.responseText)")%>
Which produces:
<script type="text/javascript">
//<![CDATA[
new PeriodicalExecuter(function() {new Ajax.Request('/qrpsdrail/grids/tablerefresh/1', {asynchronous:true, evalScripts:true, onComplete:function(request){load('26', 'table1', request.responseText)}, parameters:'authenticity_token=' + encodeURIComponent('dfG7wWyVYEpelfdZvBWk7MlhzZoK7VvtT/HDi3w7gPM=')})}, 5)
//]]>
</script>
My concern is that the "encodeURIComponent" and the presence of "authenticity_token" are generated by Rails. I'm assuming these are used to assure the validity of a request. (Ensuring a request comes from a currently active session?)
If that is the case, how can I implement this in application.js 'safely'? It seems that the built in method, although obtrusive, does add some beneficial security.
Thanks, in advance, to all who answer.

Rails generates an authentication token to protect against XSS attacks. See: ActionController::RequestForgeryProtection You can turn it off but, you're right that it's much safer to use it.
The easiest workaround that comes to mind would be to just put the authentication token somewhere at the top of your page:
<% javascript_tag do %>
<%= "var AUTH_TOKEN=encodeURIComponent(#{form_authenticity_token.inspect});" %>
<% end %>
It's obtrusive but, at least then you could use the AUTH_TOKEN variable freely in your application.js file.

Related

javascript syntax for parameters in the context of rails 6 packs

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

Rails- Pass information from view to Javascript

I want to start using websockets. I read all the docs and understand everything, but it leaves out something I need: How to pass information from view to JS?
I need to pass data from javascript to my controller. What I do not understand is, how do I get dynamically generated data in my view to the javascript to be sent?
Right now my view receives an instance variable on every HTTP request, it loops over every instance variable and makes a button which submits a hash with information extracted from that instance variable. I do not understand how to do the same thing with Javascript because Javascript will not understand Ruby classes.
This is what my code looks like now:
View/dashboards/_other_characters.html.erb
<% other_characters.each do |other_character| %>
<p><%= other_character.name %> is standing here (<%= other_character.power_level %>)</p>
<%= button_to "punch #{other_character.name}",
attacks_path(
target_type: other_character.class,
attack_type: :punch,
target_id: other_character,
target_name: other_character.name
) %>
<% end %>
This is what I would like to be able to do using JS
var task = {
name: 'Start taking advantage of WebSockets',
completed: false
}
var dispatcher = new WebSocketRails('localhost:3000/websocket');
dispatcher.trigger('tasks.create', task);
Try
<%= button_to "punch #{other_character.name}",
attacks_path(
target_type: other_character.class,
attack_type: :punch,
target_id: other_character,
target_name: other_character.name
), {id: '***', data: {name: '***', other_key: 'other_value'} } %>
Then you can access the data via jQuery data api.
When you need get dynamic data from view by client js, add data-attrs in your view dom then read it from dom API or other 3rd party js API.
In order to pass information from ruby to javascript you can use this gem: Gon, basically it transforms ruby variables and make them available to javascript on each view, take a look:
http://railscasts.com/episodes/324-passing-data-to-javascript
for any other alternative to achieve your purpose visit: https://www.ruby-toolbox.com/categories/javascript_tools#paloma

js: undefined local variable or method `current_user'

I've js file with embeded ruby code:
function MyController($scope) {
$scope.sayHello = function() {
var hello = <%= current_user.name %>;
$scope.greeting = hello;
};
}
But I've catch an error undefined local variable or method current_user which points on
= javascript_include_tag "application", "data-turbolinks-track" => true
How can I fix it? Thanks!
Use gon gem https://github.com/gazay/gon the easiest way to pass data from your rails environment to your javascript environement (in other words: from your server to your client).
in your controller
# Make sure first that current_user is not nil
gon.current_user_name = current_user.name
# As you can see we don't pass the whole `current_user` but only the data we need
# gon and javascript won't know how to use your Rails objects
# so pass only strings, integers, arrays and hashs
# (but you'll figure out all of this by your self, it's pretty natural)
in your layout (more info on gon installation can be found in gon github pages)
<head>
<%= include_gon %>
...
in your javascript
var hello = gon.current_user_name;
JS
To extend Benjamin Sinclaire's answer, you have to remember Rails is a back-end system; JS is front-end.
This means all of the Rails variables are only available in the Rails files in the backend - what your browser receives is a pre-rendered set of HTML files, populated with your data
The problem you have is that JS cannot read Rails data without having that data translated from Rails into "JS". All JS sees is the DOM - the HTML elements on your page
--
Data
In order to share variables such as current_user in your JS / front-end, you basically need to pass it through to the HTML layer
You can either do this by setting a hidden element (and setting its data attributes), or by setting the variable in your layout
As mentioned, the most efficient way to do this is to use the gon gem, which Benjamin Sinclaire has discussed

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

How to pass a javascript variable into a erb code in a js view?

I have this Javascript view in my Rails 3 project:
app/views/expenses/new_daily.js.erb
var i = parseInt($('#daily').attr('data-num')) + 1;
//$('#daily').append('agrego fila ' + i + ' <br />');
$('#daily').append('<%= escape_javascript(render(partial: 'new_expense', locals: { i: i })) %>');
$('#daily').attr('data-num', i);
I want to pass my 'i' javascript variable to a ruby partial through locals, How I can accomplish this?
As far as i know there is no way to do it directly and the reason is fairly simple too, html is executed at the server side and javascript is a client side language which means its executed in your local browser, thats why if you even try to pass a variable between the two you'll have to make a request to the server,
However this problem is tackled by calling an AJAX request, this AJAX request does the same thing as sending a new request to the server however it does that without refreshing or reloading the page to it gives the users the illusion that no request was made.
a guy asks a similar question Here
and you can learn more about AJAX Here on MDN:
Yes you can pass the value by using jquery;
<%=f.text_field :email ,:id=>"email_field" %>
<script type="text/javascript">
var my_email= "my#email.com"
$(document).ready(function(){
$("#email_field").val(my_email);
});
</script>
Simple answer is you can't. Partials are expanded at server side, and JavaScript variables are set later at client side. You could make i (as a variable name) a parameter of the partial and use it there.
render :partial => 'xx', :locals => { :variable => 'i' }
And in partial
alert(<%= variable %>);
Check out the gon gem. https://github.com/gazay/gon
It gives you a simple object you can pass variables to that will be available to your scripts via window.gon
Also referenced here
http://railscasts.com/episodes/324-passing-data-to-javascript
1) You may create a js tag with global variable in you erb template, after that you will be able to access that variable from any js file
<%= javascript_tag do %>
window.productsURL = '<%= j products_url %>';
<% end %>
2) You can pass data to data-attribute in erb template and access it by js on client side that way $('#products').data('products')
<%= content_tag "div", id: "products", data: {products: Product.limit(10)} do %>
Loading products...
<% end %>
3) You can use gon, to use your Rails variables in your js
There is a good article, read it and fine solution for your specific case
http://railscasts.com/episodes/324-passing-data-to-javascript,
more comments are here http://railscasts.com/episodes/324-passing-data-to-javascript?view=asciicast
Here's a few different options on how to do it:
http://jing.io/t/pass-javascript-variables-to-rails-controller.html
The best other answers here are right that this can't be done by passing the javascript variable into an erb partial, since it is rendered on the server, not the client.
But since anyone looking for this is probably interested in a work-around solution, which I don't see here, I will post this example that works well with Rails UJS and Turbolinks.
First, you set up your controller to return a partial as HTML:
format.html { render partial: "new_expense" }
Next, write a javascript AJAX function in app/views/expenses/new_daily.js.erb:
var i = parseInt($('#daily').attr('data-num')) + 1;
$.ajax({
url: '/daily',
type: 'GET',
dataType: 'html',
contentType: "application/html",
success: function(response) {
$('#daily').replaceWith(response)
$('#daily').attr('data-num', i);
}
});
This is going to get your Rails partial as an html fragment that you can use to replace that part of your rendered page. You can use jQuery to get your data-num attribute value, do some math on it, replace the partial in your view, and then set the attribute value again.
You may ask why go to all the trouble of getting the Rails partial and replace it on the page, instead of just getting the data attribute, doing math on it, and setting that? The answer is that this is the best, and perhaps the only way of doing something which is really essential when rendering a Rails partial using UJS while handling an asynchronous response to an action.
If you are handling an asynchronous response from your server in a create.js.erb template, then your variables (#daily, for example) are not going to reflect the work done after the request has completed (for example, if there has been processing on a background server like Sidekiq). In that case you don't have up-to-date action response variables to pass into your Rails partial in the js.erb file, but you also can't pass the javascript data response into your partial, as pointed out in this question.
As far as I know, this approach is the only way to get a fully up-to-date partial after receiving a response to an asynchronous response (not shown). This get you the up-to-date partial, allows you to get your javascript into it, and is flexible enough to work in pretty much any use case.
Let's make shure we understand each other. Your erb template (new_daily.js.erb) will be processed on the server side, ruby code will be evaluated (within <% %>), substitution made, and then resulting javascript will be sent to browser. On the client side the browser will then evaluate this javascript code and variable i will be assigned a value.
Now when do you want to pass this variable and to what partial?

Categories