I'm trying to get a json response from a rails controller and insert it into a js function. I keep getting errors:
MY CONTROLLER
def live #users present or attendees view
#presentation = Presentation.find(params[:secret])
#countdown = #presentation.start - DateTime.now()
#IF A PERSON IS A PRESENTER
if #presentation.presenter.id == current_user.id
#presenter = true
require 'json'
require 'net/http'
require 'uri'
uri = URI.parse('https://api.screenleap.com/v2/screen-shares')
req = Net::HTTP::Post.new(uri.path, initheader = {'accountid' => 'APPID', 'authtoken' => 'MYTOKEN'}) #These are correct in actual code
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
res = http.request(req)
#screenShareData = JSON.parse(res.body)
#IF A PERSON IS AN ATTENDEE
else
#presenter = false
#screenShareData = false
end
end
IN MY VIEW
<script>
<script type="text/javascript" src="https://api.screenleap.com/js/screenleap.js"></script>
window.onload = function() {
var callbacks = {
nativeDownloadStarting: [onNativeDownloadStartCallback],
screenShareStarting: [onScreenShareStarting],
appConnectionFailed: [onAppConnectionFailed],
screenShareStartError: [onScreenShareStartError]
};
var screenShareData = <%= #screenShareData %>;
var presenterAppType = 'NATIVE';
screenleap.startSharing(presenterAppType, screenShareData, callbacks);
};
</script>
In my view I also tried:
var screenShareData = <%= #screenShareData.to_s.html_safe %>;
In either case I seem to get one of two javascript errors. Either "Uncaught SyntaxError: Unexpected token &" or "Uncaught SyntaxError: Unexpected token =>"
My feeling is that it's somehow not translating the JSON the way the function expects it. Any idea how I might fix the issue?
You can pass the rails JSON variable I got from the controller by modifying the variable in the view as below:
<%= #screenShareData.to_json.html_safe %>
After that, the screenleap.startSharing function accepted the data and worked. It should be noted that I also removed the "callbacks" variable, but I isolated the change in the "screenShareData" variable as the one that fixed the issue.
You can't use irb syntax in js code
var screenShareData = <%= #screenShareData %>;
There are a few options to achieve what you want:
respond with json in your controller action and request it from client via ajax request
render this data #screenShareData in any of html tags data-attribute and get it with jQuery or vanilla js methods
UPDATE: I was wrong about that and you can inject ruby code in js. Here is an answer to your question:
var screenShareData = JSON.parse("<%= j #screenShareData.to_json.html_safe %>")
Where j is an alias to escape_javascript.
There is also another way:
var screenShareData = <%= raw #screenShareData.to_json.html_safe %>
But I would not suggest that because:
It might not work in some cases. If for example #screenShareData
has special characters and such
#screenShareData might have some code inside that will be executed in client browser
Also I suggest you to move api.screenleap.com request logic from controller action to service object.
What are you going to do if api.screenleap.com is unavailable or responds with an error?
Net::HTTP::Post is a blocking request means that if api.screenleap.com takes 5 seconds to respond then your client browser render will hold for 5 seconds. I suggest you do it async unless its desired behavior
You have different data formats in the same action response. If #presentation.presenter.id == current_user.id is true then its an array or an object. If false then its boolean. That's not cool
Related
I'm working on a Node.js app (it's a game). In this case, I have some code set up such that when a person visits the index and chooses a room, he gets redirected to the proper room.
Right now, it's being done like this with Express v2.5.8:
server.get("/room/:name/:roomId, function (req, res) {
game = ~databaseLookup~
res.render("board", { gameState : game.gameState });
}
Over in board.ejs I can access the gameState manner with code like this:
<% if (gameState) { %>
<h2>I have a game state!</h2>
<% } %>
Is there a way for me to import this into my JavaScript logic? I want to be able to do something like var gs = ~import ejs gameState~ and then be able to do whatever I want with it--access its variables, print it out to console for verification. Eventually, what I want to do with this gameState is to display the board properly, and to do that I'll need to do things like access the positions of the pieces and then display them properly on the screen.
Thanks!
You could directly inject the gameState variable into javascript on the page.
<% if (gameState) { %>
<h2>I have a game state!</h2>
<script>
var clientGameState = <%= gameState %>
</script>
<% } %>
Another option might be to make an AJAX call back to the server once the page has already loaded, return the gameState JSON, and set clientGameState to the JSON response.
You may also be interested in this: How can I share code between Node.js and the browser?
I had the same problem. I needed to use the data not for just rendering the page, but in my js script. Because the page is just string when rendered, you have to turn the data in a string, then parse it again in js. In my case my data was a JSON array, so:
<script>
var test = '<%- JSON.stringify(sampleJsonData) %>'; // test is now a valid js object
</script>
Single quotes are there to not be mixed with double-quotes of stringify. Also from ejs docs:
"<%- Outputs the unescaped value into the template"
The same can be done for arrays. Just concat the array then split again.
I feel that the below logic is better and it worked for me.
Assume the variable passed to the ejs page is uid, you can have the contents of the div tag or a h tag with the variable passed. You can access the contents of the div or h tag in the script and assign it to a variable.
code sample below : (in ejs)
<script type="text/javascript">
$(document).ready(function() {
var x = $("#uid").html();
alert(x); // now JS variable 'x' has the uid that's passed from the node backend.
});
</script>
<h2 style="display:none;" id="uid"><%=uid %></h2>
In the EJS template:
ex:- testing.ejs
<html>
<!-- content -->
<script>
// stringify the data passed from router to ejs (within the EJS template only)
var parsed_data = <%- JSON.stringify(data) %>
</script>
</html>
In the Server side script:
ex: Router.js
res.render('/testing', {
data: data // any data to be passed to ejs template
});
In the linked js (or jquery) script file:
ex:- script.js
In JavaScript:
console.log(parsed_data)
In JQuery:
$(document).ready(function(){
console.log(parsed_data)
});
Note:
1. user - instead of = in <% %> tag
2. you can't declare or use data passed from router to view directly into the linked javascript or jquery script file directly.
3. declare the <% %> in the EJS template only and use it any linked script file.
I'm not sure but I've found it to be the best practice to use passed data from router to view in a script file or script tag.
This works for me.
// bar chart data
var label = '<%- JSON.stringify(bowlers) %>';
var dataset = '<%- JSON.stringify(data) %>';
var barData = {
labels: JSON.parse(label),
datasets: JSON.parse(dataset)
}
You can assign backend js to front end ejs by making the backend js as a string.
<script>
var testVar = '<%= backEnd_Var%>';
</script>
This should work
res.render("board", { gameState : game.gameState });
in frontend js
const gameState = '<%- JSON.stringify(gameState) %>'
Well, in this case you can simply use input text to get data. It is easy and tested when you use it in firebase.
<input type="text" id="getID" style="display: none" value="<%=id%>">
I know this was answered a long time ago but thought I would add to it since I ran into a similar issue that required a different solution.
Essentially I was trying to access an EJS variable that was an array of JSON objects through javascript logic like so:
<script>
// obj is the ejs variable that contains JSON objects from the backend
var data = '<%= obj %>';
</script>
When I would then try and use forEach() on data I would get errors, which was because '<%= obj %>' provides a string, not an object.
To solve this:
<script>
var data = <%- obj %>;
</script>
After removing the string wrapping and changing to <%- (so as to not escape html going to the buffer) I could access the object and loop through it using forEach()
Suppose you are sending user data from the node server.
app.get("/home",isLoggedIn,(req,res)=>{
res.locals.pageTitle="Home"
res.locals.user=req.user
res.render("home.ejs");
})
And now you can use the 'user' variable in the ejs template. But to use the same value using client-side javascipt. You will have to pass the data to a variable in the tag.
Passing ejs variable to client-side variable:
<script>
let user= '<%- JSON.stringify(user) %>';
</script>
<script>home.js</script>
Now you can access the user variable at home.js
I am new to web development and rails as well. I created a web app for internal use in php and now am converting it to rails. Trying to find out what render does is difficult. For example I find definitions like this:
render(options = nil, extra_options = {}, &block) protected
Renders the content that will be returned to the browser as the response body.
It seems nobody told the author that you do not use a word in its definition.
I was trying to understand render because according to How to pass json response back to client that is a better way of doing the task than the approach I have tried. But without the other peices I do not know how to implement it.
Could be due to my lack of web experience so if anyone has any links to definitions thats may help please post them.
I get this error:
Error in GetData: JSON.parse: expected property name or '}' at line 2 column 3 of the JSON data
When I print the string in an alert box it appears as one long string so I do not know where "line 2" is. If I set the limit to 1 I get the same error which really makes "line 2" difficult to find.
Here is an example of the data I get back:
[{"DocumentNbr":"SS9230","DocumentRevision":""},{"DocumentNbr":"SS8640","DocumentRevision":"17"},{"DocumentNbr":"SS8618","DocumentRevision":"4"},{"DocumentNbr":"SS8630","DocumentRevision":"20"},
I don't know if the " is supposed to be spelled out as " or at least thats how it is displayed in the alert box. I do not know if thats normal or an error that is causing the JSON.parse to fail. Any other ways to check data besides the alert?
I have a javascript function to call 'GetData' in the view:
var wholeNumberData;
wholeNumberData = GetData('wholeNumber', wholeNumber);
Which looks like this (stripped down version):
function GetData(getType, param) {
var data;
var params;
params = 'wholeNumber=' + param;
data = SendRequest('wholenumber/index', params);
return data;
}
function SendRequest(source, params) {
var http = new XMLHttpRequest();
http.open("GET", source + '?' + params, false);
http.setRequestHeader("Content-type","application/json");
http.onload = function() {
//alert('in function');
}
http.send(params);
alert(http.responseText);//Works
return JSON.parse(http.responseText);//FAILS
}
The route wholenumber/index points to an index.html.erb cionatining this:
<% #list = Wholenumber.where("DocumentNbr LIKE ?", params[:wholeNumber] + "%").limit(10) %>
<%= #list.to_json(:only => [:DocumentNbr, :DocumentRevision]) %>
This is kind of an unusual way to do it, but you could just add html_safe to your to_json method and it should work how you have it.
<%= #list.to_json(:only => [:DocumentNbr, :DocumentRevision]).html_safe %>
If you want the control to render JSON, rather than trying to parse JSON from html, you can have the controller action do something like this:
def action
#list = Wholenumber.where("DocumentNbr LIKE ?", params[:wholeNumber] + "%").limit(10)
render json: #list.to_json(:only => [:DocumentNbr, :DocumentRevision])
end
The Rails Guides have a more thorough walkthrough of Rails rendering
This question already has answers here:
How to pass Ruby variables to a JavaScript function in a Rails view?
(6 answers)
Ruby on Rails - Send JavaScript variable from controller to external Javascript asset file
(2 answers)
Closed 8 years ago.
i'm new in Rails and in a controller i have:
class PagesController < ApplicationController
def home
#temp = "Hello"
end
end
I have read that i must put the javascript code in application.js (tell me if true) and i have:
window.onload=function(){alert("<%= j #temp %>")}
Obviously that alert print the string "<%= j #temp %>"
How can i pass the variable #temp to the javascript so that the alert can print Hello?
Thanks
I wrote an article on how to pass Ruby objects to the client. Ryan Bates also has an excellent RailsCast on passing data to JS.
Add a div to your view that corresponds to your the PagesControlle#home action that will not be visible when you load the page but will contain the data stored in the Ruby objects:
# views/pages_controllers/home.html.erb
<%= content_tag :div, class: "temp_information", data: {temp: #temp} do %>
<% end %>
Load the page with this div included and view the page source. You can see your Ruby objects stored in the .temp_information div. Open up the JavaScript console to access the Ruby objects as JavaScript objects:
$('.temp_information').data('temp')
You do not need to add your JS to a JS partial, you can also use the asset pipeline.
I do something similar to, but simpler than gon. I have the following in my ApplicationController.
def javascript_variables(variables)
#javascript_variables ||= {}
#javascript_variables.merge!(variables)
end
Within a controller action I can then do something like
def some_action
javascript_variables(user: current_user)
end
In my ApplicationHelper I have something like this
def javascript_variables(variables = nil)
#javascript_variables ||= {}
#javascript_variables.merge!(variables) and return if !variables.nil?
output = ''
padding = #javascript_variables.keys.group_by(&:size).max.first
#javascript_variables.each do |variable, value|
output << "#{variable.to_s.ljust(padding)} = #{value.to_json},\n "
end
raw "var " + output.strip.html_safe.gsub(/\,\Z/m, ';')
end
and finally in my layout's <head> I have
<script>
<%= javascript_variables %>
</script>
This gives me something like this (from a real example in my application)
<script>
var pageModule = "site/index",
isCustomer = false,
utype = "normal",
isAnonymous = true,
keyboardShortcuts = false,
pubnub = null,
requestToken = "3zj974w074ftria3j";
</script>
Take a look at this.
http://tech.thereq.com/post/17243732577/rails-3-using-link-to-remote-true-with-jquery-ujs
One of the easiest ways is to use js.erb file, where you can do ruby tags to access variables that you defined in the controller action.
You need to use a respond_to block in the controller action, specifying the action to be able to respond to javascript.
items_controller.rb
class ItemsController < ApplicationController
def action
respond_to do |format|
format.js
#format.html {} # These are for allowing other types of formats to be responded to.
#format.json {} # But they are not necessary for using this js.erb way of doing things.
end
end
end
/views/items/action.js.erb
$(div).html('The cat has erased your page');
I have the following variable defined in my Rails controller:
$PATH
In JavaScript I would like to change the value of this variable:
<script>
$("#resetDefaults").click(function(){
$PATH = '3'; //try 1
<%= $PATH %> = '3'; // try 2
});
</script>
I have tried both of the above statements and can't figure out how to do it.
A global variable is only global in the Ruby code that is executed on the server.
You're running JavaScript code in the browser. That code has no direct access to variables on the server.
If you wish to change some state (variable) on the server, you need to call a Rails controller method from your JavaScript code. I.e., you need to do an AJAX call to the server from the browser. Something like this:
$("#resetDefaults").click(function() {
$.ajax({ url: "<%= url_for(:action => 'update_path_var') %>" });
return false;
});
Then in the controller you have something like:
def update_path_var
$PATH = 1234
render :nothing => true
end
http://api.jquery.com/jQuery.ajax/
http://apidock.com/rails/ActionController/Base/url_for
BTW, in general using global variables in Ruby is not considered good coding practice, unless there is some very specific reason for it.
There is no way to achieve that. I think you should do some introduction to web programming course.
I'm trying to get my JSON from my controller to my view. In my controller I am doing:
#nodes = Node.all
#json = #nodes.as_json(:only => [:ID, :Lat, :Lon])
In my view I have tried:
1) var stuff = <%= #json %>
2) var stuff = <%= #json.to_json %>
3) var stuff = <%= #json.to_json.to_json %>
and all of those give me an error. I usually get an "Unexpected Syntax Error &" or "Unexpected Syntax Error {"
I have also tried using jquery and using respond_to within the controller, but that doesn't seem to work either.
My thoughts are that getting json to the view shouldn't be a big issue and shouldn't require jQuery, and currently, my page source looks like:
var stuff = [{"node":{"ID":1301499692582,"Lat":42.3605063113369,"Lon":-71.0870862191138}},{"node":{"ID":1301499691515,"Lat":42.3605147089149,"Lon":-71.0870533282532}},{"node":{"ID":1301431075499,"Lat":42.3605456103,"Lon":-71.0875239075536}} etc
I dont understand the " symbols (maybe thats where the syntax error is coming from) but when I do render :json => #nodes.to_json, the page renders a normal json that is valid:
[{"node":{"ID":1301499692582,"Lat":42.3605063113369,"Lon":-71.0870862191138}},{"node":{"ID":1301499691515,"Lat":42.3605147089149,"Lon":-71.0870533282532}},{"node":{"ID":1301431075499,"Lat":42.3605456103,"Lon":-71.0875239075536}}
Note: I've also tried doing var stuff = '<%= #json.to_json %> but when I do var json = JSON.parse(stuff), it gives me an illegal token error.
Can someone please help me with this? Thanks so much!
This is Rails html-encoding your string as is default in Rails 3.
You need to mark your JSON as html_safe:
var stuff = <%= #json.to_s.html_safe %>
Note that .to_s is needed because as_json gives Hash instead of string. You could do this instead:
# in controller
#json = #nodes.to_json(:only => [:ID, :Lat, :Lon])
#and in view
var stuff = <%= #json.html_safe %>
I think you need to put quotes around it, then you can ask jquery to parse the string into JSON.