How to retrieve a value from an AJAX call with Rails? - javascript

I have this scheme:
JS:
jQuery.validator.addMethod(
"check_membership",
function() {
console.log('A');
$.ajax({
type: "POST",
url: "/subscriptions/check_validity",
dataType:"JSON",
data: {coupon: "12345"},
});
console.log('<%= #aaa %>');
},
"mmmmm"
);
and Rails action:
def check_validity
#aaa = 'xxx'
respond_to do |format|
format.js { render :text => #aaa }
end
end
My goal is to display in Javascript the value from Rails - #aaa, but the output of
console.log('<%= #aaa %>');
is just an empty space...
But I am not sure what the proper workflow should be here (I need to pass just a kind of information like "yes"/"no").
Thanks guys!

Ajax sends a params variable of your data to the controller, just like a form for a new record. In your example, to retrieve the coupon value, you pass params the key you established in your ajax call:
def check_validity
value = params[:coupon] # returns "12345"
...
end
As noted in another answer, this will not yield the #aaa value in your console.log, or anywhere in your javascript. These variables are interpreted on the server side, but javascript only works on the client side (unless you're using server side javascript, but that's a horse of a different color). This can be confusing because we use Ruby variables in Views, but Views are interpreted on the server, before they are sent to the client. Javascript is not.
Once you pass a variable to Rails, through the params value, you'll need to send any new information back to the client, which is looks like you're trying to do with :text => #aaa. Many ways to tackle this issue, but you could start with the Railscast:
http://railscasts.com/episodes/324-passing-data-to-javascript
and also
http://railscasts.com/episodes/136-jquery-ajax-revised

Hm, a lot of confusion going on here:
console.log('<%= #aaa %>');
Is mixing server side and client side stuff. If you
render :text => #aaa
in rails, you don't get a variable named #aaa in your browser.
I'd recommend rendering json to the browser anyway...

Related

Rails update element based on AJAX request?

I've been reading a lot about Rails and AJAX and 5.1 Unobtrusive javascript. It explains a lot about responding to Rails version of AJAX calls with a .js file for example.
However what im wanting to do isn't serving up an entire .js file, it's simply updating an element after a <% link_to %> POST request. From my understanding setting remote: true submits it as a AJAX request.
Essentially I have a "Post" which a user can like via a linked Like button. This sends a POST request to the "Post" controller which updates a post to liked and adds a like to the post.
Unfortunately to see the effects of the post being liked (Which is simply that the link changes color as well as the font-awesome icon) you need to refresh the page. I basically want it to update without needing refresh.
I "think" based off what i've read I need to make a respond do and respond via .js to the request with a .js file in the view I want to update (for instance if the controller action is called "like", maybe a like.js.erb file in the view im updating?). But I don't want to serve an entire new page..or would this simply just run the .js?
Then I could do something like $('i.fa-icon#id').style.color = "blue" or something? (Im assuming I can send data from the controller to the .js.erb file?). Not sure the best way to do this, don't rails elements a lot of times have some sort of data-attribute or something (Im still a beginner at this).
Your description is quite correct!
Opposed to the other answer, you don't even need a event listener but as you said you want to have a respond_to in the controller.
So starting from the html:
# post/index.html.erb
<div id="like-button">
<%= button_to "Like this post", post_path(#post), remote: true %>
</div>
Note, that when you use a button_to helper it'll be a POST request by default.
If you click it, it'll go to the controller#update, which you want to change to this:
#posts_controller.rb
...
def update
#post.save
respond_to do |format|
format.html { redirect_to post_path(#post) }
format.js # <-- will render `app/views/posts/update.js.erb`
end
end
Note: the format.html is rendered when JS is disabled.
Now in the scenario that JS is enabled, it executes the app/views/posts/update.js.erb file. It can look like this:
const likeButton = document.getElementById('like-button');
likeButton.innerHTML = '<%= j render "posts/liked-link", post: #post %>';
What is the last line doing? Of course, you can change the style directly with the JavaScript, but you can also render a new partial - and this you will create in a new html file:
# app/views/posts/liked_link.html.erb
<div id="like-button ">
<p>"You liked this post!" </p>
</div>
I just changed the link/button to ap now, but of course you can do whatever you want.
Hope that makes sense :)
Not sure if I understand the question, but if you want to update like button:
What you want to do is to add an event listener to the button, and when clicked it makes a POST request to whatever route handles the likes(with the correct parameters) and your controller should respond with the like object (or whatever in the database gets stored). Have your post request on success method to grab the like button and change it to whatever you want it to look like
$(“#like-btn”).click(function(){
Rails.ajax({
url: "/some/url/to/like/controller",
type: "post",
data: [your post data],
success: function(data) { $(`#${ data[“btn-name”] }`).attr(“color”, “blue”; }
})
}
You can stick this script right in the bottom of the html page
You don’t have to do it exactly like this, just giving you an idea of how to set up the pattern of having JavaScript and Ajax handle the post request and updating of the frontend instead of using html buttons

Rails 4/AJAX GET data from controller

I posted a very poor question about this earlier, so I am reposting and making it MVCE.
I'm building a messaging service with Rails and AJAX. So far I can submit a message through a form, it will update in the HTML DOM, an AJAX POST method will send it to the controller, and the controller will save it in the database.
Now I need to add an AJAX method that will GET the message that was just submitted -- so that other users (in other browsers) will be able to view it.
Currently, and this is a hack job way of doing it, in my JS code I set a timeout that calls an AJAX GET function every half second. Is there a better way to do this -- as in, once the controller saves the message can it call the AJAX function? The AJAX code looks like this:
function retrieveMessages(){
var message;
<%debugger%>
$.ajax({
type:"GET",
url:"<%= messages_get_path %>",
dataType:"json",
data: { what_goes_here: "blah" }, //this is the part I do not understand -- see below
success:function(data){
message = data;
console.log(data)
}
});
setTimeout(retrieveMessages, 500);
}
$(document).ready(function(){
//get messages
setTimeout(retrieveMessages, 500);
... more irrelevant
The line data: { what_goes_here: "blah" } doesn't make sense to me. What is the syntax for the controller to send data back to be stored into data:? Furthermore, from the console I can see that what_goes_here is being passed as a parameter to the controller -- again this doesn't make sense to me.
My route looks like this get 'messages/get', :to => 'messages#get' (this might be incorrect?)
rake routes shows
messages_get GET /messages/get(.:format) messages#get
And as of now, I don't have anything in my controller other than a respond_to because at this point I'm just trying to call the controller. What is the syntax to send data back to the AJAX method?
def get
debugger
respond_to do |format|
format.html
format.json {render json: #variable} //is this #variable being passed to the AJAX call?
end
end
UPDATE
This makes more sense to me... the AJAX method simply calls the def get function. The def get function then finds the message in the database, and stores it in an instance variable. Subsequently, I can add some Javascript code that will insert it into the DOM. However I must have something wrong in my routing because I'm getting (in the console) http://localhost:3000/messages/get 404 (Not Found)
What you are doing, as you suspect, is not effective. The more users are online the more will be load from these refreshing requests, most of them probably returning no new data.
You should consider more active way of notifying your browsers about changes on the server. One option is to use ActionCable.

Use a controller variable in javascript (Ruby on Rails)

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.

AJAX request can't get instance variable from controller in Rails application

I'm trying to get data from my controller into a javascript file in a rails application. The html immediately invokes an ajax request using the select option and the organization id as parameters.
In a before_filter I have
def set_org_id
if params[:id].present?
#org_id = klass.find(params[:id]).id
else
#org_id = 0
end
end
And in the js file I have:
$.ajax({ url: "/admin/analytics/filter",
type: 'GET',
data: {
time_frame: selectedId,
organization_id: <%= #org_id %>
}
})
If I hard code a number as the organization_id everything works fine, but when I try to pass the data from the before filter, I end up with no id in the page.
I should add that the index route is admin/analytics/. The filter action is admin/analytics/filter. The user never navigates to that page, only ajax hits the filter route to get relevant data. Could this be that the ajax request is being send before the instance variable is set? If so, what is the proper solution?
Your JS won't be able to access your #instance variablesunless you call them from your controller itself. The problem here is that if you're loading the ajax to access an instance varialbe - which simply won't work.
Let me explain...
JS
Javascript is known as a client side language - meaning it provides you with the ability to access elements in your HTML / DOM with relative impunity. The problem here is that Rails / Ruby, much like PHP, is server-side, and consequently is only able to provide rendered data to your browser
This means that calling the following simply won't work:
data: {
time_frame: selectedId,
organization_id: <%= #org_id %>
}
As explained, the reason for this is that you cannot access the #org_id from your Javascript. Firstly, you don't know if the #org_id variable will be set (in case you want to use the Rails helpers), and secondly, your JS won't be able to access the variable anyway (because it's Rails)
--
Fix
The purest fix for this is to somehow create the data you need in the DOM. I see from your answer that you have set a hidden field for your form. A much better way to do this is to set an HTML5 "data" attribute, or to use an id
You'd be better doing this:
<%= form_tag route_path, data: { org_id: #org_id } %>
This will give you the ability to call:
$(document).on("submit", "form", function(){
$.ajax({
...
data: {
time_frame: selectedId,
organization_id: $(this).data("org_id")
}
});
});
I was able to solve this by passing the data to a hidden field in the html.erb page.
<%= hidden_field_tag('org_id', #org_id) %>
Then in the javascript refer to the data through the selector.
organization_id: $('#org_id').val()
I don't love this, but at least it works.

Can't use js.coffee via $getJSON upload params

I need to use JS pass a params to the rails controller:
def page
#select = Firstpage.where( :pid=>params[:par_id])
respond_to do |format|
format.html # page.html.erb
format.json { render json: #select }
end
end
The js.coffee code:
fetchselect=(val) ->
$.getJSON('firstpages_controller.rb', par_id:val )
$('.homeNav').find('.unactive').click ->
id = $(this).attr('id')
fetchselect(id)
Is the coffeescript server-side? If it's being served to the client, then you should not be making direct requests to the controller - rather, you should be making a resource request which the rails server should resolve to the right controller.
To elaborate: when you're generating rails links on the server for the client, you'd probably so something to the effect of pages_path, which generates a url to the effect of "http://base_path/pages". This is pretty fundamental to rails - each object the user has access has RESTful representation, or in simpler terms there's a url to identify it. JSON representations of a resource are no different - to get a JSON, the url you pass to getJSON must be formatted the same way. As far as the client is concerned, "pages_controller" doesn't exist - it's a background detail that they have no direct access to.

Categories

Resources