Using Devise with React

Linked Projects:

Lesson code -

In this module, we’ll add user authentication using the Devise gem.

At the moment, our app doesn’t have user accounts, so anybody can view, add and edit appointments.

To make it useful for more than one person, we’d at least need basic user accounts.

We want to be able to sign up, log in and make your own private appointments.

Let’s start by adding the Devise gem to our Gemfile (at the bottom).

gem 'devise'

Then, from the console, run:


Then run:

rails g devise:install

It will generate the necessary initializer and config files.

Then we can add the default URL options to the development environment config file. This is used when Devise generates the emails for confirming accounts and for resetting passwords.

config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

Next, let’s generate a user model with Devise by running:

rails g devise User

This will create a migration.

Then we can run an extra command which will create a user.rb model file:

rake db:migrate

Now, let’s connect it to AppointmentsController.

We just need to add a before_action call at the top of the file:

before_action :authenticate_user!

Now, none of these routes is public. You need to be signed in order to access them.

Now we need to restart Rails and then when I refresh the page, I get redirected to a login page.

[screenshot: 1:47]

You can test the sign-up page and create a new account.

So, I get logged in and redirected to the homepage. But we’re still seeing the old appointments because we haven’t linked the appointments model to the user model.

[screenshot 1:57]

So, let’s do that by creating a migration.

In the console, run:

rails g migration AddUserToAppointments user:references

Then migrate the database:

rake db:migrate

In the model, we need to add in user.rb...

has_many :appointments

...and in appointment.rb

belongs_to :user

So, now we have a one-to-many relationship between the two models.

Now in the appointments_controller, we need to restrict all our queries on the appointment model to just the current user.

So let’s replace Appointment. with  current_user.appointments. As an example, our code which started as

@appointments = Appointment.order('appt_time ASC')


@appointments = current_user.appointments.order('appt_time ASC')

And let's do that in all the actions by using the find and replace tool.

[screenshot 2:51]

Now if we reload the page, the old appointment won't appear.

[screenshot 3:02] 

Now we can try this function by making a new appointment. Add a title, appointment time, and submit.

[screenshot 3:09-10]

The appointment works.

We can also view it and edit it.

[screenshot 3:16]

We have the user model working now.

One thing you’ll notice is we don’t have any indication that the user is signed in. Also, we do not have a sign-out link.

So let’s add that.

Let’s show the current user’s email address and a sign-out link in the header.

Now, we could add it in our AppHeader React component. However, for this module, I’m going to do it outside React in the index view file, simply because we can directly use some Rails helper methods and we don’t have to worry about handling session data in the client.

But we will also look at doing this in React in detail in the API module, so if you want to skip this and look at that instead, feel free to do that.

Let’s open the index file and I’m just going to paste in a couple of lines for showing the current user email and sign-out link at the top:

- if user_signed_in?
    =link_to('Sign out', destroy_user_session_path, method: :delete)
= react_component('AppRouter')

Now if I refresh the page, I’ll see it.

[screenshot 4:22-3]

And I’m able to sign out by clicking this link.

[screenshot 4:24]

We’ve implemented just our appointments UI in React and kept user accounts and session stuff outside. 

This is a common pattern especially if you’re new to using React in your Rails apps. You can choose which bits you want to port to React and which parts you want to keep in Rails because it’s easier.

But as I mentioned before, we will also look at doing this in React in detail in the API module which you should also visit.

Liked this tutorial? Get more like this in your inbox