This is Part 1 of a series of posts about my experience building my first Rails applicaiton. You can read the prelude to the project here.
Recap
For my first Rails app, I am going to build a fitness tracker that let's users sign up for an account where they can create routines and store exercises in them. They can then create more, edit and/ or delete those routines and exercises.
Initial Setup & Wireframing
The setup experience with Rails was pretty smooth. Unlike Sinatra, which doesn't usually come with an out-of-the-box setup process (with the fabulous exception of the 'corneal' gem, Rails does:
rails new flatiron_fitness_rails_app
This will create all the necessary files and folders to get the project to run on a server, on Rails!
I went ahead and made a flowchart that maps out the model associations and a typical user experience:
As shown above, a User can have many Routines. We have a join-table, RoutineExercise, that allows for each of a User's routines to have many exercises, which can also have many routines. One of my project requirements is for my join-table to have a least one user-submittable attribute (something besides a foreign key like routine_id
). So I went ahead and added a reps
and sets
column for each RoutineExercise
that is created for a Routine
.
NOTE: Some of the file names I have in this image weren't used in the actual codebase
Here, I'm mapping out what a simple user experience would look like in the app.
- The user starts up the server and are directed to login or signup for an account
- At this point, the user can opt for third-party authentication (though some
:provider
like Github or Facebook) instead of coming up with a new set of login credentials.
- At this point, the user can opt for third-party authentication (though some
- They are then taken to an index page that shows a list of their routines. From there:
- They could create a new routine, or...
- Click on a specific routine to see more information
- Inside an individual routine, they are shown a list of exercises; each one can be clicked for more information.
- Whether they're looking at a specific exercise or routine, they can either:
- edit it (and be redirected back to the appropriate view)
- delete a routine (along with any associated RoutineExercise objects, but not the associated Exercises themselves)
- Inside an exercise show page, the user should be able to either remove it from the routine or delete it entirely (which will cause other instances of the Exercise object to be deleted).
Devise and OmniAuth
Next, I wanted to fulfill the user auth requirement for the project by going with the devise
gem. Devise takes care of all the user- and session-related tasks including things like setting session cookies upon login, third-party authorization with OmniAuth(more on that, soon). I don't need to worry about creating a users_controller
, sessions_controller
or a separate migration for creating the users
table -- Devise takes call of that!
To be honest, this was hard to set up at first. If you want to use more than one provider
(more than one existing account to log in from), you have to do the following for each provider:
Register your Rails app with the provider of your choice by heading to their developer pages and following the setup instructions.
Each provider comes with their own special
omniauth-<provider_name>
that you must include in your Gemfile. In my opinion, it's best to do both that and also include the general 'omniauth' gem so that, for example, you're assured your login link for Facebook is omniauthable.In
config/initializers/devise.rb
, there is a section in the source code where you must set your configurations for your omniauthable provider against the environment variables that are ( safely supplied from an.env
file.You have to refactor your
config/routes.rb
so that youruser
routes have access to anomniauth.rb
(orcallbacks.rb
) controller (make sure you create the appropriate file incontrollers
;). This gives yourusers
table access to those provider links (allowing 3rd-party login/signup).
After much toil, it's incredibly worth. I can now simplify my life by not having to create a new set of login credentials by sticking with a set I use a lot more often.
Now, the only caveat I've found with this is that, imagine if a user could choose between Facebook and Google as an option for login/signup and they chose Google. If they log off and then try to login through Facebook, they are weirdly redirected to the signup page. In other words, they can only login through Google since that was the provider they chose the first time.
For now, I'm going to let that go and just note in the README
that when a user first starts the application and creates an account, if they want to do so through 3-rd party authentication, they must stick whichever they choose. *
** I'm almost certain there is a way to fix that issue and make it so that a user can flexibly login to the same Rails application from multiple providers. There are websites that can do that. But there are also websites that don't have that flexibility. I think that, for a first Rails application, I should appreciate that I got this far and that there is always room to grow.*
End of Part 1.
Happy Coding!
Resources
How To Configure Devise and OmniAuth For Your Rails Application