Friday, April 1, 2016

Learn how to use Devise gem well



There are lots of tutorials about Devise gem, explaining how to install it, how to create the views and how to generate the model used to authenticate in your application. If you are just looking for this, please don't waste your time reading this article. Just watch this video and you'll learn the basics.

But if you are facing a particular issue when using Devise gem in your Rails application, this article is going to show you deal with it.

My Rails application must insert, update and delete the objects described in Devise model

Let's understand the problem first.

Assume you have an entity named User in your system and this is the entity Devise will authenticate. In other words, users log into your app.

When this happens, the structure of Devise is prepared to create (register) new users, update them, remove them... Well, Devise is prepared to fully control users in your app. But...

But, what happens if logged users are allowed to register other users?

Devise assumes a user tries to register only when it not logged. Register is a requisite to log into an app, then one is not supposed to register (create a new user) when logged! Then, if you try to create a new user when a user is already logged, you'll receive a :require_no_authentication error, will be redirected from your register method to another place and the registration will fail.

A friend of mine gave up using Devise after facing this issue. And I saw many people asking about this at StackOverflow. It is really a bothering thing! I suffered this myself and researched a lot before finding this solution I'm going to show you. I even restarted a system from zerro, just because I thought Devise should never be user over a pre-existing model, but this is not true.

So, let's correct all this stuff in easy steps:

(We are going to assume we are using User as our authentication model, but all these steps are similar if you use Admin or Contact or any other model. You must only do the appropriate changes.)

1) Create new methods

Still assuming you are authenticating User, go to app/controllers/UsersController.rb and create new method called user_new, user_create and user_update. Copy the contents of new, create and update, respectively, to these methods;

2) Copy app/views/users/new.html.erb to app/views/users/user_new.html.erb;

3) Copy the partial app/views/users/_form.html.erb to app/views/users/_user_form.html.erb;

4) Edit app/views/users/new.html.erb and app/views/users/edit.html.erb to render the new partial, i.e., change

<% render '_form' %>

to

<% render '_user_form' %>

5) In the partial _user_form.html.erb change the line

form_for @user

to

form_for(@user, url: '/users/user_create'


6) Now, edit config/routes.rb and right below the line who reads

devise_for :users

create scoped routes for the new methods you created

  devise_scope :user do
    get   'user/user_new', to: 'users#contact_new'
    get   'user/user_edit/:id', to: 'users#user_edit'
    post  'user/user_create', to: 'users#user_create'
    patch 'user/user_create/:id', to: 'users#user_update'
end

Now we are ready to, even logged, create and edit users in a Devise authenticated app. But if you have user parameters beyond those used by devise, i.e., if you  want users to have fields like :name, :address or something like that, don't forget to permit these parameters in your Users controller.