This post is a journal for the process of creating a website in Rails. Some degree of familiarity with Ruby and Rails by the reader is assumed. Our objective is to create a website that utilizes authentication and authorization (and also allow authentication from an outside service). It will also utilize nested resources and routes. For this project, we’re going to build a site that can manage events. We want our users to be able to create events that other users can sign up to attend, and tag their own events with tag categories. Some code will be intentionally left out but my full code can be found on my repo, linked at the bottom of this post. Let’s get started!
Getting Started:
First, we create our models and migrations. I use regular old rails generators to create the files with
and fill in the changes needed afterwards.
Continue to generate and write out migrations for the User, Tag and Comment models. Our comment model will also serve as a join table that can have an attribute :content to hold the text for a comment in addition to tying a user_id to an event. We’ll also want a second join table for Events and Tags and a model for EventTag, since Events can have many Tags, and Tags can have many Events.
And also another join table for the users and events tables so we can build out the feature to allow users to ‘attend’ events. We’ll call this join table Schedules.
Now to add Devise to handle our authentication needs. Include the devise gem in our Gemfile. We’ll also include Pundit and Omniauth while we’re at it to handle roles and outside authentication service. I’ve decided to use GitHub for this site.
Run bundle to install the gems
GitHub omniauth requires that we get GITHUB_KEY and GITHUB_SECRET keys from github for authentication. You can obtain these directly from github by logging in or creating an account and creating a new application. Get the keys from GitHub and create a new a file the site’s root directory called .env (note: this is a file with no name that has an extension of .env). The dot-env gem included above will allow rails to grab the values from the .env file.
Now add the keys to the .env file, replacing <YOUR_KEY> AND <YOUR_SECRET> with your values from GitHub (or whatever provider you chose)
Then add Devise to Users so that it can do it’s magic
Then to add Omniauth capability to our Users
Add roles to our User model. Normal users will be create by default. Admins can modify everything but will not be able to be created from sign up.
We’ll also need to make changes to our config/devise.rb file to include a config line that will allow Omniauth to work with Devise. We add this line to the devise.rb file instead of omniauth config since we are using Devise for authentication.
Then we want to include our migrations to create our tables
Now to make sure that our routes are setup properly. Remember we want to make use of nested routes for our comments, since a comment belongs to a user. In addition to setting up a Static controller to handle our home page, we’ll also want to create a new controller to handle omniauth callbacks for omniauth sign ins. This controller will handle all the data that is sent back from github (callbacks)
Create the omniauth callbacks controller. I’ve decided to create a app/controllers/users folder and stick a newly created omniauth_callbacks_controller.rb which inherits from the Devise’s omniauth controller.
Modify the User.rb model file to look for or create users from GitHub. You might want also want to add a couple of simple validations along with defining pundit roles with enum and devise options to allow omniauth. The below also has some ActiveRecord association macros needed for interacting with other models.
Building MVC:
Now to build out the rest of the models, views, and controllers. We start by building out the rest of models with the proper association macros
The event class will have a bit more code to help validate attributes and also make the time objects for the event more readable in our views
Controllers:
We want anyone who comes to the site to be able to view our site, but only users who are signed in to be able to create and go to events. We can authorize actions by defining policies. We can use Pundit to craft these policies in a app/policies/resource_policy.rb file. Here’s one for our Event.
Now, only users who created the record, in this case our event, can make changes or create events, while moderators and admins who are signed in can do the same to any event. Now our controller actions will need a way to call on these policies. We can do that with authorize
Views:
To finish up this post, I’ll include the code for the event views, which utilizes ‘<%= render @event %>’
When <%= render @events %> is called, Rails will automagically look in the app/views/events folder for any _event.hmtl.erb file. It will pass each element in the @events array and perform the code in the block in the file, whether it’s a single event in a #show action or many events in #index action. app/views/events/_event.html.erb
Conclusion:
This has been a quick guide to creating a Rails app with authentication and authorization. This post is by no means extensive or complete, but you can find my full repo on github.