Reputation: 2135
I am new to backbone.js. I am developing a rails application using "backbone-on-rails" gem. I have included 3 models and rendering views uisng backbone. It worked fine. Now i want to add authentication to my app using devise, after the user has signed in only my app needs to be rendered otherwise i need to redirect to login page.
I have added devise
gem for it.
Can someone please help me on how can i check whether user has signed in or not, if user hasn't logged in need to redirect to devise sign_in page using backbone?
Thanks in Advance
Upvotes: 0
Views: 631
Reputation: 1437
I needed to implement a backbone login in rails with devise. Note that for my purposes I did not need user registration as well, since I wanted to have just one admin user, created manually in the terminal by me.
Basically as long as you make an AJAX post request to the right devise route, devise will handle the login for you (assuming of course you went through the devise setup process correctly). In Backbone you can make this post request using a new model save.
This tutorial helped me set up my Backbone model and view (FYI: the tutorial also goes over what you need to do in order to add registration functionality). The tutorial had some more advance backbone setup (for example it uses backbone.marionette and backbone.modelbinder) which although very useful, I did not want to get into. Below is my simplified version of the tutorial to the bare core of what you need.
Create a model with the urlRoot
that matches your devise login route. For most people that go with the standard User model, the urlRoot
route below should work. Note my code is written in coffeescript
class MyCoolBackboneApp.Models.UserSession extends Backbone.Model
urlRoot: '/users/sign_in.json'
defaults:
email: ""
password: ""
toJSON: ->
{ user: _.clone(@attributes) }
Note that devise expects the params to be wrapped inside 'user' which is why we had to overwrite the toJSON
method
Then in your view, all you need to do is save the model together with the login credentials. Of course every person might have a different success and failure callback, but here is a very basic implementation:
events:
'submit form': 'login'
initialize: =>
@model = new MyCoolBackboneApp.Models.UserSession()
render: =>
$(@el).html( @template() )
@
credentials: ->
{
email: @$('#email').val(),
password: @$('#password').val(),
remember_me: 1
}
login: (event)->
event.preventDefault()
@model.save(@credentials(),
success: (userSession, response) =>
window.location.href = "/"
error: (userSession, response) =>
message = $.parseJSON(response.responseText).error
alert(message)
)
You should also read this tutorial about how to set up devise ajax authentication.
After you complete the above tutorial, you should be able to save your UserSession
model with the right credentials (as I do in the view) and login successfully (assuming you have a saved existing user in your Database). You'll know you've logged in successfully when you get redirected to your success callback.
Then in the controllers in the rest of your app, you should be able to use the devise helpers: user_signed_in?
or current_user
etc etc.
(If you are logged in but get an undefined method error for these helpers, try to add: include Devise::Controllers::Helpers
to your controllers).
Finally Alex P's response can then walk you through how to use the user_signed_in?
boolean in your Backbone views.
Upvotes: 0
Reputation: 6072
Backbone's a frontend-only framework, so it doesn't have a concept of authentication. All the source code is sent to the web browser, and all the network connections are plain to see, so a malicious user can trick your app into thinking it's logged in, even if it isn't. So you'll still need to check access permissions on the server.
What you can do, though, is have your Backbone app detect whether it thinks it's logged in, and change its display based on that. For instance, you could use Devise's user_signed_in?
helper to add a data attribute on your body tag, and hook into that. Something like this in your app/views/layouts/application.html.erb
:
<body data-user-signed-in="<%= user_signed_in? ? "true" : "false" %>">
And then, maybe your Backbone router is going to look something like this:
myApp.Routers.Router = Backbone.Router.extend({
routes: {"": "showFrontPage"},
isSignedIn: function() {
return $('body').data('user-signed-in') === "true";
},
showFrontPage: function() {
var view;
if (this.isSignedIn()) {
view = new myApp.Views.MainAppView();
} else {
view = new myApp.Views.SignInView();
}
view.render();
}
});
Alternatively, you could look directly for a session cookie. That seems a bit more brittle to me, though; if the name of your application changes, or Rails changes how it names its cookies, your app's going to break. But in that case, your isSignedIn()
function is going to look more like this:
isSignedIn: function() {
return document.cookie.indexOf("_Railsappname_session") > -1;
}
If you want to check your user at various points of your app, you could easily write a controller method that returns the result of user_signed_in?
as a JSON object. But it's better not to rely on this; rather than calling /user/is_signed_in
and then /posts/create
, far better to do one call to /posts/create
and have that return a 401 Unauthorized if the user's not logged in.
As for logging in itself, you can adapt Devise to work via JS so you can login via AJAX, but it's not as straightforward as you might hope. There's a tutorial here.
Upvotes: 2