Calling Devise from a javascript bookmarklet - javascript

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

Related

Run Javascript code when Devise authenticate_user fails

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.

Rails API - helpers for AJAX

I have a normal rails app website, but on some pages I need to use AJAX.
I already have some working AJAX Javascript code using jQuery, but so far I haven't used any rails helper to do that, writing strings corresponding to paths manually.
But is there a more convenient way to do it in javascript ? Suppose I have a javascript function which takes an ID as argument, and must call an AJAX action. So far I've been doing it this way
var url = "/tags/tagID"
function getTag(tag_id){
$.get(url.replace("tagID", tag_id) +'.json')
.fail(function(data){
alert('Oops error !');
})
.success(function( data ) {blabla ] )
}
Is it possible to rename the .js to .js.erb and use path helpers ? So I could get rid of this url variable and write
routes.rb
resources :tags
tags.js.erb
$.get(tag_path("tagID").replace("tagID", tag_id)....
Or is there a more convenient way to do this ? I only need very little AJAX, so I don't want to use a frontend framework (Angular, etc.), just jQuery
EDIT My scenario
A user searches for a given tag thanks to an autocomplete searchbar. This searchbar will return the ID somehow.
The user can select several tags this way, and their IDs will be stored in an array. Now, upon clicking a button, I want to send a query to a non-RESTful (with the ID array as parameter) controller action via AJAX. For now I will focus on sending one item at a time (so just one ID string), for it is easier/more reactive.
This action is actually going to look in my models for projects and ingeneers that possess this tag, and return a JSON with formatted results.
Yes, you can use *.js.erb to use Rails helpers. Rails provides some handy helpers to work with Ajax. Normally with rails you can use them by using the the tag remote: true.
In your case something like
<%= link_to 'Tags', tags_path(<tag.id>), remote: true %> (roughly),
Read more about using Rails helpers with Ajax here, and this explains it nicely.
Update
Rails is using CSRF token to validate requests (except GET), so if you are going to use pure HTML/JavaScript, you want to add the token to your request. Have a look at this post on the same.
I agree there is no out-of-the-box way of doing that, but there are few workarounds.

Continue Form Post with remote => true / Controller Action after Devise Login

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.

Accessing Rails Session Variable from Backbone View

This might be a very simple question, but I could not find the answer for it. How should I access a rails session variable from javascript/jQuery (from a Backbone view)? Most likely this is not the best practice, but this is not a problem for me.
Thank you,
Alexandra
You can use the gon gem. It allows to send data automatically with each request and let it be accessible from javascript.
For example, after including the gem in your Gemfile, you can add a before filter to your ApplicationController:
class ApplicationController < ActionController::Base
before_filter :set_gon
...
protected
def set_gon
gon.my_session_variable = session[:my_session_variable]
end
end
In your application layout, section head of your html:
<%= include_gon %>
Now you can read this value from your javascript:
alert(gon.my_session_variable)
This way you only include data specific to the request in your ajax response, and all your extra info is available from the gon variable.
No, session variables reside on the server, so there is no direct method to access the session variable with javascript/jquery.
Your best bet is to make an ajax call with javascript/jQuery to the server to an url you have defined to return the session variable you want in for example JSON format so you can directly access it in Javascript:
{
"sessionVariableName": "sessionVariableValue"
}
And no, this is definitely NOT a best practice. Session variables should stay on the server IMO.
Just in case this might help someone ...
While ejosafat's answer is valid, the main reason why I needed to access rails session variables from Backbone was to be able to modify them. Since I did not know for sure what I wanted, my question was ambiguous to start with (for example, accessing the session variables did not have to be a direct process). The way I ended up achieving my goal was by using the following four-step process:
make sure to initialize the needed rails session variables in the sessions_controller.rb file
send the values of the session variables that you want to be able to modify to backbone (in my case, the session variables were accessed by the used rails controller, then sent to the corresponding rails view, and then to the backbone app.js file, which made them accessible to the necessary backbone views)
create a function on the rails side (in the used controller) that can update rails session variables based on GET requests from backbone. For example:
def modify_session_variables
if params[:taskParentId]
session[:task_parent_id] = params[:taskParentId]
end
end
each time a backbone variable that represents a session state is changed by the user, send an ajax request to the server with the updated value(s) for the rails session variable. For example, one of my backbone models will update a session variable when one of its attribute is modified:
saveAsParentTask: function() {
var self = this;
$.ajax({
url: '/modify_session_variables',
type: 'GET',
data: {
taskParentId: self.getId()
},
async: false,
success: function() {
App.filtersState.setSubtreeParent(self);
}
});
},
This process will save the user choices as long as (s)he does not log out of the application. A bit complex, but works the way I want it to.

AJAX with Ruby on Rails?

This is probably a really dumb question with a simple answer but...
I am working on a project where I need to use AJAX to send/receive information. I am using Ruby on Rails (which I am pretty new to), but rather than using the helper methods or the built in functionality in the 'defaults' Javascript file, I need to do this manually in my own Javascript.
I believe that ultimately I will want to send a request with a JSON object, then have the controller return another JSON object containing the requested information.
The problem is that I cannot seem to find the syntax for sending something to a specific controller method, with parameters, directly from Javascript - everything I Google ends up being tutorials for using the Rails AJAX helper methods.
Depending on the version of Rails you're using, you can do the following:
Install the jrails plugin. This will replace all the Prototype javascript in your application with jQuery. This means you now have access to all the jQuery libraries, but it won't break your existing rails helper stuff (remote_form_for, etc).
Now you can use the jQuery AJAX to make any AJAX requests you want to make. A simple example would be something like below:
//Let's get a specific post by id
$.ajax({
type: "GET",
url: "/posts/123",
success: function(data){
//put the data in the DOM
}
});
Then just add the appropriate respond_to in your controller:
PostsController < ApplicationController
def show
#post = Post.find(params[:id)
respond_to do |w|
w.json { render :json => #post.to_json }
end
end
end
if using jQuery is an option for you, jQuery.ajax will solve your problem.
[and for those who likes to say jQuery is not solution for everything, i know that. i'm just giving him an option].

Categories

Resources