I'm trying to do something very similar to this question...
In summary, I have voting logic on a page, but to vote, I require you to sign in. The voting logic for a signed in user simply does a :method => :post, :remote => true call to a controller method, saves the vote, and does a respond_to :js to a JavaScript HAML template which replaces HTML using jQuery.
For an unauthenticated user, this currently works such that the anonymous user clicks "vote", is redirected to the Devise login page, logs in, and gets redirected back to the page they were on to vote again. But, this is a bad user experience.
How would I change this so that the last step simply continues to process their vote?
I have existing HTML views for the voting logic, and would prefer to simply continue the processing of the vote, redirect to the page where the user voted from, and flash a message saying the vote was successful. However, if it's just "as easy" to do this using JavaScript / jQuery, I'd be open to this. The only piece I want to avoid is re-creating the Devise templates in JavaScript.
The difficulty in this type of redirect lies in the fact that forms are submitted via post requests. Rails' redirect_to method makes a get request, which prevents you from submitting forms.
This solution does not care about the type of authentication you use. This is what I did in the past (this is pseudo code to illustrate the process):
If the user is not signed in, attach a hidden field to the form and assign its id to a random string:
- unless signed_in?
= hidden_field_tag :submit_token, id: "form_#{rand}" # just generate something random
In your controller filter that checks if the user is signed in, check for this param, and set a session hook if it's present.
session[:submit_token] = params[:submit_token] if params[:submit_token].present?
Then in your create.js.erb (the template that's rendered after an ajax sign in) check for this session value. If it's present, use it to find the form and submit it via jQuery.
- if session[:submit_token]
$('#' + session[:submit_token]).parent('form').submit();
- session[:submit_token] = nil
Ideally you would create helper methods to set and remove the session[:submit_token] values.
The reason you can't use something more traditional, like a store_location method is because they can't deal with post requests. So you can't redirect back and continue the original post request before it was diverted to the login.
Related
I am building a movie recommended system. I want when a user login and rate a movie, the rating and movie name as well as user name will post to another page without going to that page automatically, i mean without pressing anything. How can I do that?
You can do that by executing an ajax request (after clicking the vote-button), which sends data (you can define the data to be what you want - rating, movie and user) to a php script that you will have to create.
the php script will read the posted data that the ajax has sent and can insert/update the database.
This way, the user will not be redirected. he won't even notice.
You can achieve this by using some kind of ajax requests triggered by vote event or callback.
When I move to page which should be accesible only for signed in user, the Devise render sign in form. I have a nice styled notification which tells user that he is signed out, and I would like to show it without redirecting to sign in page. I have file user.js.erb which contains working Javascript code, but I don't know how to run it. I was trying to rewrite the authenticate_user method, but without success.
def authenticate_user!
unless current_user
end
end
I've tried respond_to with format.js, but it hasn't worked. I don't need ready code, but I would really appreciate if anyone can direct me in the right direction.
To do this you need to authenticate user via ajax. There is no other way because when you press on 'login' or submit button, browser sends data to server and waiting for html reply that your server generates.
Please, check out this post.
So here is the desired behavior I'm trying to get:
User goes to a password change web page.
User fills out form and the form PUTs to our REST server.
After a successfully PUT, the user is redirected to the "My Account" page with a message saying, "Password successfully changed".
If they refresh their "My Account" page, the password message should go away. (I.e. it is a one time message.)
Here are solutions I've tried (unsuccessfully):
1) Using JQuery to perform an AJAX PUT to the REST server. This works fine for the PUT, but the redirect has to be in the onSuccess JavaScript and if it passes a message on the URL to the My Account page, then that message hangs around after refresh.
2) Using a traditional form. However, this won't do a PUT ( method does not support put, on post and get). I could do a POST, but that is "wrong" from a REST perspective, because I'm updating the user account record, not creating a new record. The redirect and one-time message could all be handled server side with this solution (RESTlets, Servlets and/or JSP).
Is there are good solution out there? Or must I change my PUT to a POST?
You may do PUT using a traditional form using JavaScript. The only trick is to flash a temporary message. I've seen web frameworks that use a sort of temporary session state for this kind of stuff which requires little effort on your part. If you don't have that available, the trick would be to store a temporary session in the database and reference it through a cookie. It is not straight forward, and that is why web frameworks can really help you in this situation.
The typical setup is as simple as this:
$('form').submit(function () {
$.ajax({
url: 'service/api',
data: $('form').serialize(),
type: 'POST'})
.done(function () {
// perform redirect
});
On the server side you set the temporary session state and delete when complete.
I have a javascript bookmarklet which used to work as a single user mode. So how it used to work is I would click on my bookmarklet on the browser, and it would inject a remote javascript on my server. This second javascript in turn makes an ajax call to my rails server with a code that looks something like this:
$.post(
"http://192.168.1.2:3000/stuffs",
{stuff: JSON.stringify({"link":address})},
"json"
);
This code used to work when I was working on my project without an account. But today I added a devise authentication system. So now the system has users. In my controller code I have
before_filter :authenticate_user!
def create
puts current_user
#stuff.user = current_user
...
end
This doesn't work. current_user returns nothing. I am just trying to figure out whether there's an existing session (whether someone is signed in), and then want to create an entry under that user. In this case, a user has_many stuffs and stuff belongs to a user. The rest of the site works fine. It just seems trying to access using bookmarklet doesn't preserve a session.
Anyone know what's going on?
I believe you need to pass authenticity token parameter to params sent by jQuery, like this:
$.post(
"http://192.168.1.2:3000/stuffs",
{
stuff: JSON.stringify({"link":address}),
authenticity_token: <%= "#{form_authenticity_token.inspect}" if protect_against_forgery? %>
},
"json"
);
More docs on form_authenticity_token can be found here: http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html#method-i-form_authenticity_token
Apologies if this question is a bit convoluted.
I want a Django page to display a banner message sometimes. Sometimes the user will arrive via window.location.href, and then I would like the banner to display, with a message determined by the action the user just performed.
Details:
I have a site-wide javascript listener that listens for scanner input (which presents as keyboard input).
When it triggers, using jQuery I return or check out the item, dependent on its state. I do this via an Ajax POST request.
Then I immediately take the user to the item's page on my site. I do this by setting window.location.href to the item's page, inside the response handler of the POST request. The item shows as available or checked out, but I want to show the user another message too...
...I want to show a banner saying 'Item checked out' or 'Item returned'.
The last item is where I'm having problems: how do I 'tell' the item page what message to show, and when to show a message at all? People will also arrive at item pages not via the scanner.
I could set GET parameters (?t=checked_out or ?t=returned) but that feels messy.
I could use cookies but that feels even messier.
If I POST to the item page (which also feels wrong) with a t=checked_out parameter, wouldn't it be good Django practice to then redirect somewhere else, rather than display the page?
Perhaps I'm just too hung up on the last point.
Anyway, the basic question is: How best can I pass hidden variables to a page via window.location.href?
Thanks for your help. I have the feeling there's something fundamental that I've yet to learn here :)
Why do an AJAX request at all for step 2/3?
You asynchronously POST, then redirect.
Can you do a normal POST with info about whatever the javascript did, add some message in your session in the django backend (and have the item view load it), and do a server redirect to the item page?
The django way would definitely be to do it in django sessions.
If you must, your method should be possible anyways:
pass extra bits of information TO django in your ajax post
set your "hidden variabes" to the django session (request.session['myvar'] = 'ajax_posted_stuff')
javascript redirect (but seriously, it would be best to have the server redirect)
pull "hidden variables" from the django session (ajax_posted_stuff = request.session['myvar'])
Example:
def ajax_view(request):
if successful_response():
request.session['show_banner'] = True
return JSON # or whatever you were doing before
def item_view(request):
context = {}
if request.session.get('show_banner'):
context['show_banner'] = request.session.pop('show_banner')
return render_to_response("mytemplate.html", context)
# item.html
{% if show_banner %}
<h1>Banner shown!</h1>
{% endif %}
Why do you think using a cookie would be messy? I'd say go for cookies if you can. You can read cookies from window.document.cookie.
As an alternative to cookies, the cleanest solution could be to use the URL hash:
http://example.com/page#co
You can easily check for the presence of the hash with window.location.hash.