gon is a gem for ruby on rails to pass data from controller to view's javascript.
It works fine,just pass data,and watch one variable.
but when I have normal data(no need dynamic watch ) and data1 (need watch )teogeher,problem happens.
Gon watch all variables instead of only watch the gon.watch.data1.
That cause refresh time very very long (7k ms plus)
web page always hang.
anyone face this problem before? how to solve this?
code in my controller
class GmapsController < ApplicationController
def index
#i=0
#Nstatic=Array.new(NoiseDevice.all.length) {Array.new(4)}
#Vstatic=Array.new(VibrationDevice.all.length) {Array.new(4)}
#vabrdevices = VibrationDevice.find(:all)
#vabrdevices.each do |vabrdevice|
#Vstatic[#i][0]=Project.where(id: vabrdevice.project_id).pluck(:client_name).first.to_s
#Vstatic[#i][1]=vabrdevice.latitude #
#Vstatic[#i][2]=vabrdevice.longitude #
#Vstatic[#i][3]=VibrationDevice.where(id: vabrdevice.id).pluck(:cont_value).first.to_s
#i+=1
end
#i=0
#noiseDevices = NoiseDevice.find(:all)
#noiseDevices.each do |noiseDevice|
#Nstatic[#i][0]=Project.where(id: noiseDevice.project_id).pluck(:client_name).first.to_s
address=Project.where(id: noiseDevice.project_id).pluck(:jobsite_location).first.gsub(/\s+/, "+")
#Nstatic[#i][1]=noiseDevice.latitude #
#Nstatic[#i][2]=noiseDevice.longitude #
#Nstatic[#i][3]=NoiseDatum.order(:updated_at).where(noise_device_id: noiseDevice.id).pluck(:leq).first.to_s
#i+=1
end
gon.nstatic=#Nstatic
gon.vstatic=#Vstatic
end
def ndataupdate
#test=Array.new
#test=VibrationDevice.pluck(:cont_value).to_s
gon.watch.test1=#test
end
end
Instead of update my test1 only, it updates all data which is loaded from database in this controller. even if I delete
gon.nstatic=#Nstatic
gon.vstatic=#Vstatic
gon will load all data retrieved from database in this controller instead of part of it.
In order to make it display only refresh part , I delete all retrieve data function ...
maybe it's not answer, but maybe it somehow helps (comments are too long),
so, you could specify manualy url for updating variable like:
gon.watch('test1', {interval: <ms>, url: '<url>'}, '<callback>')
for checking available variables in your ndataupdate action you could write:
gon.all_variables
also you could try cleaning variables with:
gon.clear
Related
The classic way to work with Rails & Ajax is always something that looks like this:
// JS - let's assume this submits to dummies#create
$(form).submit()
# Dummies Controller
def create
#dummy = Dummy.new(dummy_params)
respond_to do |format|
format.js
end
end
# /views/dummies/create.js.erb
$("page").append("<%= escape_javascript(render partial: 'dummy_view' ) %>");
# /views/dummies/_dummy_view.html
<h1><%= #dummy.name %></h1>
I've always been curious, because the above seems to create a random create.js.erb file with very little meat... is there a reason (e.g., it's terrible convention, or terribly insecure or whatever), why you should NOT instead just render the view directly back to ajax?
// JS - basically takes responsibilites of create.js and puts it into the always
$.ajax(...).always(function(xhr, status){
$("page").append($(xhr['responseText']))
// responseText contains the partial rendered by the controller action
})
# Dummies Controller
def create
#dummy = Dummy.new(dummy_params)
render partial: 'dummy_view'
end
# /views/dummies/_dummy_view.html
# unchanged
<h1><%= #dummy.name %></h1>
NOTE above is pseudo-code, apologies for minor errors. The conceptual idea & question remain unchanged, though.
The create.js.erb is not random, is the view for the action with the expected format.
Generally, you may not have a view so simple (You may have different selectors other than "page", you may have some extra js code to be executed after or before the append), a js view/script is the general solution for an ajax request to give the response full control over what to do.
You could have what you want, but it will just work for your particular case when the selector is always "page" and you only want to append html to that element. Nothing prevents you from doing that (though you might want to use a custom ajax request and not rails' one since it sets js format by default and executes the response's script).
The convention is that a rails' remote request renders a js script, you can move out of the convention if you want. You'll lose a lot of flexibility with your approach as is (like... what if the create action fails an you need to display errors?).
I want to use my controller variable in my javascript.
Since this cannot be done straightforward. I use gon gem. https://github.com/gazay/gon
With this what I do is in a before filter of my base controller (Which acts as a before filter for all the controllers) I do gon.variable_name = value And in my js file I use gon.variable_name. This works fine for full page reloads.
But the variable is not getting updated for ajax request.
Say for example:
On page reload, in my controller I do
gon.variable_name = value1
and in my js, gon.variable_name gives me value1.
After a ajax request in my controller I do
gon.variable_name = value2
and in my js, I still see gon.variable_name as value1 only.
Is there any way I could update gon.variable_name in a ajax request?
Thanks
You can use the watch: true switch for gon:
#app/views/layouts/application.html.erb
<head>
<%= include_gon(watch: true) %>
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
def update_vars
#value1 = User.count
gon.watch.value1 = #users_count
end
end
This is what the documentation says. I don't agree with it, but should work.
It looks like ajax polling which is notoriously inefficient.
--
To give you some context, you have to remember that gon basically creates a small hash of javascript in your layout, populating it with the gon variables you've assigned in your controller:
<script>
gon = {
value1: "test",
value2: "test"
}
</script>
We've used it before here:
The reason this is important is because this gon JS variable is invoked at runtime -- meaning that it remains static until you reload the page.
The way around this is to either dynamically reload the gon variable values (using watch above) or pass the new value through your ajax request (like Sergio recommended in the comments):
#app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
def update
respond_to do |format|
format.json { render json: {value_2: "test"}.to_json %>
end
end
end
You'd then be able to use it as follows:
$.ajax({
url: "/update",
success: function(data) {
var value2 = data.value2;
}
});
I have to initialize gon for every request inorder to update the variables.
include_gon(:init => true)
in the response of every request solved the problem.
Extra tip:
For those who use ajaxify rails gem you can call this helper method in the ajaxify_extra_content method and in the content_inserted callback you can append this to the head tag to get it work in a generic way.
Thanks all for your suggestions and help.
There are two ways I know of to pass variables defined in a controller (/action) to JS...
The official way is
.js.erb:
var banana = "<% #banana %>"
Another way (that I'm currently using is)
.html.erb
<span id="banana-variable" style="display:none"><% #banana %></span>
.js
var banana = $("#banana-variable").html()
This js file is loaded on multiple actions/views across the controller. It makes sense to me to not use a .erb extension: users cache it the first time they hit any action/view in the controller. They then won't have to download different versions of the file when they browse to different pages. Am I right?
Yes, are right. The javascript will be cached on the client's browser.
Still you want to send data on the 'js' or script files you can use this gem called Gon.
http://railscasts.com/episodes/324-passing-data-to-javascript
I recommend you use gem 'gon', which is thoroughly introduced in RailsCast. It makes your controller cleaner. Your method will make it more troublesome if you're trying to pass an array or hash to js.
I think your issue is that you are using <% %> which will execute the code, instead of <%= %> which will execute the code and render the result back into the template.
With Gon you can access the page only after the html page is loaded. From what I understand it uses web page as a proxy to transfer data from rails server to javascript.
But if you want to use the variable at any point of time you want, you can do an ajax(post) request from javascript to the rails controller and retrieve the value as json.
Example:
AJAX Request:
$.ajax({
type: "POST",
url: <PageURL>,
async: false,
dataType: 'application/json',
success: function(data){
data = JSON.parse(data);
},
});
your "data" will contain the returned value.
On the controller side it should be:
Controller:
def <PageURL>
render :json => {:result => <value_you_want_to_return>}
end
Do not forget to define the controller's path in routes.rb file.
I'm working on an application in which a certain model is updated from a number of different locations using remote forms. I'm looking for a pattern to dynamically call the right JS callback after updating this model.
With a normal form this can be solved by passing a redirect url in the form itself and then redirecting to this url in the controller. The remote form side is harder: Should I pass a file name? Should I pass an arbitrary string and then switch on that string in a single .js.erb file? Any other suggestions?
Is this just a sign that the application should be restructured to prevent updating the same model from more than one location?
No it's fine If you can call the same controller action from different locations.
Your options:
1) Preferably this controller action can give the same response and will work for the different locations, ex. it just updates a container with a id which is present in all those locations.
2) You noted that redirects made things easy in the past, consider adding the following to your application controller:
def js_redirect_to(path, flash_messages = {})
flash_messages.each { |type, message| flash[type] = message }
respond_to do |format|
format.js { render :js => "window.top.location='#{path}';" }
end
end
This is the same signature as the normal redirect_to, it just allows you to redirect from a js request. Note that if you use turbolinks the js should be 'Turbolinks.visit(url);'.
3) If you really can't handle it generically like the options above, you could pass your JS namespace of the location you are submitting from in the form, and the controller calls the same method for all locations, it's just a different namespace. Ex:
Let say one location is from Pet administration, then in assets pet.js:
var pet = {
load = function() {
your page load js...
},
... more functions...
post_callback = function(html_segment1, html_segment2) {
this is where you handle the form callback for pets...
$('some_element').html(html_segment1);
$('another_element').html(html_segment2);
}
}
Construct more like these for other locations of your app. Using JS namespaces like this is anyway a good idea. Then your form submits a parameter :location => :pet to the controller, which responds with:
... your JS code that all pages should execute...
html_segment1 = "<%= escape_javascript(render 'some_partial') %>";
html_segment2 = "<%= escape_javascript(render 'other_partial') %>";
<%= #location %>.post_callback(html_segment1, html_segment2);
4) Use a widget gem, most popular is apotomo or cells.
5) Just use a case in the controller to render different views.
Hope this helps, let me know if you need clarification.
I receive a google ID from an Ajax call and then want to use that ID to update a button on my view.
Here is the code in new.js.erb, which is linked to a new.html.erb.
Problem is, I don't know how to pass the variable's content. Restaurant is a json. The alert returns the correct ID and when I search my db on the terminal with the returned google id I find the restaurant.
Here is the code:
alert(restaurant["google_id"]);
var google_id = restaurant["google_id"];
$("#rating_bar").html("<%= escape_javascript(render 'reviews/buttons/full_profile_rate_restaurant', :google_id => "+google_id+".html_safe) %>");
What happens is that the variable being passed is the string "google_id" instead of the combination of letters and numbers that is the google ID. I've tried multiple approaches, this is just one of many wrong one - I think this question is pretty easy for anyone who knows their JS really well.
It is not possible to pass a JS variable to the ruby partial.
As Ryan Bigg explained for the same type of problem here, its not possible to send the variable while rendering that partial. We need to work out some thing else. Even i also had the same issue once.
Alternatively,
if that is google_id is only a variable to display in the partial, then update those divs manually after rendering that partial.
like
$("#rating_bar").html("<%= escape_javascript(render 'reviews/buttons/full_profile_rate_restaurant', :google_id => "sample_id") %>");
// Now update the required elements
$("#what-ever-ids").text(google_id);
or just create some other action in that controller, and call send an ajax request to that action, and there you will have this js variable, and in that js.erb file render the same partial which you actually want to update with the google_id variable.