Web Development with Rails and Git Tutorial

Demo 13: Adding User Logins, Authentication, and Authorization

▶️ Play from the beginning (~1 hour, 10 minutes)

In this demonstration, I will explain how to add user login features to a web app using the Devise gem. In particular, users will be able to register and log in to the web app with a username (their email address) and password. The system will allow some pages to be accessible without logging in, but will require that users be logged in to access other pages. Furthermore, the system will restrict access to data based on whether or not a user “owns” that data.

▶️ 1. Installing and Configuring the Devise Gem

  1. ▶️ Prep: Review the Devise Gem README, giving special attention to the “Getting started” section.
  2. ▶️ Install the Devise gem by adding gem 'devise' to the Gemfile and running bundle install.
  3. ▶️ Add devise to the project by running rails generate devise:install. Inspect the output of the command, giving special attention to the instructions.
  4. ▶️ Configure as per the instructions printed to the console. This step should involve only setting the mailer configuration. (The root route should already have been set and notice/alert messages should have already been added to application.html.erb.)
  5. ▶️ Generate a User Devise model class using rails generate devise .... Apply the generated migrations using rails db:migrate. Inspect the generated model class and routes (see rails routes).
  6. ▶️ Test and debug: Run the web server, and test some of the new Devise routes (e.g., sign_up and sign_in).

▶️ Check-in Changes: changeset, snapshot

▶️ 2. Applying Bootstrap Styles to Sign-In and Sign-Up Forms

  1. ▶️ Add the Devise views to the project (to customize them later) using rails generate devise:views. Inspect the added view files.
  2. ▶️ Update the view for the Sign In page (see view devise/sessions/new.html.erb) to be consistent with the other views in the app. Test and debug as necessary.
  3. ▶️ Update the view for the Sign Up page (see view devise/registrations/new.html.erb) to be consistent with the other views in the app. Test and debug as necessary.

▶️ Check-in Changes: changeset, snapshot

  1. ▶️ Prep: Review updated wireframe diagrams, giving special attention to the new text/buttons on the nav-bar. Also, review the README page for the Devise Gem (see https://github.com/plataformatec/devise), giving special attention to the “Controller filters and helpers” section, and review the Bootstrap Navbar documentation and the Bootstrap Pricing example.
  2. ▶️ Update view layout application.html.erb, adding to the right side of the nav-bar text/buttons corresponding to the user’s login status. If the user is currently logged in (see Devise helper user_signed_in?), display their email (see Devise helper current_user) and a “Sign Out” button. If the user is not current logged in, display a “Sign In” button.
  3. ▶️ Test and debug: Run the web server, and test out the newly added buttons.

▶️ Check-in Changes: changeset, snapshot

▶️ 4. Requiring Authentication for Certain Pages/Actions

  1. ▶️ Prep: Review the README page for the Devise Gem (see https://github.com/plataformatec/devise), giving special attention to the “Controller filters and helpers” section.
  2. ▶️ Update the base class ApplicationController to enforce that users must be signed in to access all pages (see Devise filter before_action :authenticate_user!). Test and debug as necessary.
  3. ▶️ Update the controller classes to loosen this restriction for certain controller actions (see the filter skip_before_action :authenticate_user!, only: ...). Test and debug as necessary.

▶️ Check-in Changes: changeset, snapshot

▶️ 5. Adding User Login Seed Data

  1. ▶️ Update the db/seeds.rb to create some users. All that is needed is to set the User attributes email and password. Note that this is a little strange because password is not actually a model attribute.
  2. ▶️ Test and debug: Reset the database (rails db:reset), run the web server, and confirm that the seed user was created correctly. Further confirm the state of the database by using the Rails Console and by inspecting the SQLite database.

▶️ Check-in Changes: changeset, snapshot

▶️ 6. Adding User Ownership of Records

The goal of this part is to make the user who creates a child object using the child CRUD pages the owner of that object, and by extension, all objects that belong to that child.

  1. ▶️ Prep: Review an updated class diagram, giving special attention to the new has-many association with User class on the has-many side (as opposed to the belongs-to side).
  2. ▶️ Add an association such that each User object has many child objects. This change involves generating a migration that adds a foreign-key column to the child database table (see rails generate migration ...) and adding has_many and belong_to declarations to the User class and the child class, respectively.
  3. ▶️ Update the db/seeds.rb to add instances of the newly created association. Note that a child object must have an associated User object to be valid. Thus, calls to save! need to wait until the association links are instantiated and all objects to be saved are valid. Test and debug as necessary.
  4. ▶️ Update the child controller’s index action to retrieve only the current user’s child objects, and update the child controller’s create action to instantiate an association link to the current user (see the Devise current_user helper). Test and debug as necessary.

▶️ Check-in Changes: changeset, snapshot

▶️ 7. Updating Test Fixtures and Adding Unit Tests with User Logins

  1. ▶️ Update test/fixtures/users.yml to have two User records. Include only their email attributes. Give special attention to the fact that the default User fixtures are broken and why.
  2. ▶️ Update the fixtures for the child class of User to add association links.
    • Oops! Should have named reference attribute using the name from the belongs_to declaration and not the name of the foreign key column.
  3. ▶️ Update test/models/user_test.rb to add a unit test for a User object that should be valid.
  4. ▶️ Test and debug: Execute the tests (see rails test) and fix issues as necessary.
    • Oops fixed! Corrected child fixture to use the name from the belongs_to declaration and not the name of the foreign key column.

▶️ Check-in Changes: changeset, snapshot

© Scott D. Fleming 2018 • Made with GitHub Pages and Markdown