AJAX with Rails 3 and jQuery? - javascript

I've been trying to make a console-based calculator (kind of like Try Ruby) in using Rails 3 and jQuery. To do so, I've been trying use AJAX so that the console sends JSON or XML whenever you type enter, it waits, receives the response from the server and renders it.
Unfortunately, I have no clue as to where to start. My Google searching has lead to only tutorials that deal with the client side of things, and other tutorials only address Rails 2.
My client-side code is something like this:
function evaluate(line, report) {
// ajaxy stuff goes here
report("Whatever stuff I get back"); // this will display on console
}
I have no idea on what to do for the Rails code.
So how do I go about implementing AJAX with Rails and jQuery?

You probably want to do something like this
in your client code:
function evaluate(line, report) {
// ajaxy stuff goes here
$.post("/path/to/controller/action.json", { line: line, report: report } ,function(response){
//process JSON response here
});
}
in your rails controller (which you will have mapped to http://yourserver/path/to/controller/action)
def action_called
# do stuff with params[:line] and params[:report]
respond_to do |type|
type.html # render html view
type.json { render :json => { #response_data_as_a_hash }.to_json }
end
end

Perhaps start here
Ultimately your ajax call will hit a controller action just like any other web request. Your controller can respond with JSON or XML or even determine the response format by the extension on the url.
Good Luck.

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.

Dojo request.post to Rails Fails

I'm converting a website from Symfony to Ruby on Rails and am finally down to my javascript pop up email contact form. I don't want to rewrite the form or the java script as it took a lot of work to get it to work in the first place. That will be phase two.
Here's where I'm having the problem:
sendBtn = new Button({
label: "Send",
onClick: function(){
if (emForm.validate() == true){
// Post the data to the server
request.post("/contact/create",
{data: domForm.toObject("contact-form"),
// Wait 2 seconds for a response
timeout: 2000
}).then(function(response){
emailDialog.hide();
alertDialog.set("content",response)
alertDialog.show();
});
}
}
},"submit-btn");
I know it gets to the request.post as I copied the line "email.Dialog.hide()" just before it and it hid it. I later added code to catch any errors. It goes there immediately and not after the two second timeout. I'm using dojo here, by the way. So I suspect it doesn't like the "/contact/create" as it's the only thing I changed.
In my routes.rb I have:
get 'contact/create'
Do I have the right information in my post? If not how do I get there? The javascript is included in application.html.erb so it can be invoke from all pages on the site.
In case it's pertinent, my contact_controller.rb is currently just this:
class ContactController < ApplicationController
def create
respond_to do |format|
#format.html {}
#format.js {}
format.json { render :json => {:response => 'Amazing, it works'} }
end
end
def show
end
end
Take a look at your network tab in dev tools, it should tell you why it is failing post... I'd say try adding handleAs: 'json' option to your request.post. For more on dojo/request, read this
As it turned out, I had the right path in the request.post statement. I found out my copying the Javascript into my html.erb file so I could use
<%= contact_create_path %>
in it's place. I ended up getting the same value so that wasn't the problem. I then checked my Firebug console. Rails sends a nice dump of the problem. I was getting a 404 error. The problem was that I was doing a post and there was no route for it. So I changed the routes.rb file from
get 'contact/create'
to
post 'contact/create'
This might cause me other problems later on if I want to do a non-Javascript version.
I then got another error:
ActionController::InvalidAuthenticityToken in ContactController#create
Through the help of Stackoverflow I found the fix. I added the second line below:
class ContactController < ApplicationController
skip_before_filter :verify_authenticity_token
...
Again, this solution may cause other problems. Skipping verification doesn't seem like a good thing. I had a number of other problems getting the whole process to work, but their specific to my application.

How do I change pages and call a certain Javascript function with Flask?

I am not sure if I worded my question correctly. I'm not actually sure how to go about this at all.
I have a site load.html. Here I can use a textbox to enter an ID, for example 123, and the page will display some information (retrieved via a Javascript function that calls AJAX from the Flask server).
I also have a site, account.html. Here it displays all the IDs associated with an account.
I want to make it so if you click the ID in account.html, it will go to load.html and show the information required.
Basically, after I press the link, I need to change the URL to load.html, then call the Javascript function to display the information associated with the ID.
My original thoughts were to use variable routes in Flask, like #app.route('/load/<int:id>') instead of simply #app.route('/load')
But all /load does is show load.html, not actually load the information. That is done in the Javascript function I talked about earlier.
I'm not sure how to go about doing this. Any ideas?
If I need to explain more, please let me know. Thanks!
To make this more clear, I can go to load.html and call the Javascript function from the web console and it works fine. I'm just not sure how to do this with variable routes in Flask (is that the right way?) since showing the information depends on some Javascript to parse the data returned by Flask.
Flask code loading load.html
#app.route('/load')
def load():
return render_template('load.html')
Flask code returning information
#app.route('/retrieve')
def retrieve():
return jsonify({
'in':in(),
'sb':sb(),
'td':td()
})
/retrieve just returns a data structure from the database that is then parsed by the Javascript and output into the HTML. Now that I think about it, I suppose the variable route has to be in retrieve? Right now I'm using AJAX to send an ID over, should I change that to /retrieve/<int:id>? But how exactly would I retrieve the information, from, example, /retrieve/5? In AJAX I can just have data under the success method, but not for a simple web address.
Suppose if you are passing the data into retrieve from the browser url as
www.example.com/retrieve?Data=5
you can get the data value like
dataValue = request.args.get('Data')
You can specify param in url like /retrieve/<page>
It can use several ways in flask.
One way is
#app.route('/retrieve/', defaults={'page': 0})
#app.route('/retrieve/<page>')
def retrieve():
if page:
#Do page stuff here
return jsonify({
'in':in(),
'sb':sb(),
'td':td()})
Another way is
#app.route('/retrieve/<page>')
def retrieve(page=0):
if page:
#Do your page stuff hear
return jsonify({
'in':in(),
'sb':sb(),
'td':td()
})
Note: You can specify converter also like <int:page>

Redirect to a rails path using AJAX

how do I refresh a rails path with an error message using ajax. I'm waiting for a callback from a payment API and if I get an error I want to reload the page and show the error. Problem is I'm using ajax. How can I pull this off ?
Refreshing the page to display a simple feedback error is completely unnecessary and long-winded. A much cleaner, and more direct method, is to use js to update the dom within the callback.
A very very simple demonstration:
$(".errors").append('<li>My error</li>');
In the name of simplicity, do that (or something similar within javascript), don't redirect just to display an error.
If error is persisted on database, you can use window.location on callback function in order to relaod the page with errors.
In the action that responds to the AJAX request you can do
flash[:alert] = "My error"
And then have the action render the redirect as such:
render js: "window.location.href = '#{my_named_route_path}'"
Or, you may want to write a method to abstract this, such as:
app/controllers/application_controller.rb
def redirect_to_via_xhr_if_applicable(url, options = {})
flash[:info] = options[:info] if options.key?(:info)
flash[:alert] = options[:alert] if options.key?(:alert)
flash[:notice] = options[:notice] if options.key?(:notice)
if request.xhr?
render js: "window.location.href = '#{url}'"
else
redirect_to(url)
end
end
Then you can just make this call from your AJAX (or non-AJAX) action:
redirect_to_via_xhr_if_applicable(my_named_route_path, alert: 'My error!')

Categories

Resources