Rails-Project-Build

Posted by Elijah wines on July 30, 2020

The Rails Project Build I created for my portfolio project tasked me with creating a web application using the Ruby on Rails Framework. The project required implementing my knowledge of MVC model, many to many relationships between models, validations, scope methods, user authentication, omniauth login, nested routing, and validation errors. This sounds (and kind of is) like a lot of work, but the Rails Framework makes it simple and easy to manage a web application with these features.

I started off with the M in MVC which of course stands for Models. The models are most likely the trickiest part of the framework because they require relationships between each other if you want them to interact with one another. For example in my project I created 3 main models - User, Project, and Task. These models relate to each other like this: The User Model has many projects, has many tasks, and has many project tasks through tasks (because a task belongs to a project). The Project Model belongs to the User, has many tasks, and has many Users through tasks (because a task is created by a User). The Task Model belongs to the User and belongs to the Project. Creating these relationships between models is probably the most difficult yet important piece in creating a highly functional Rails application. In order for me to (kind of) understand this I had to research multiple examples of this “many-to-many” relationship between models and at a certain point it just kind of clicks.

Another important piece of the models is implementing the sql database into them. What I mean is, creating a table in the sql database to represent the models. For example, my User table in the database has the column names “name, email, and password_digest”. This means every user has a name, email, and password stored in the database when using this application. This allows for user authenticating. When a User wants to sign up, they provide a name, email, and password so that when they come back to the app for a second time we can search them up in the database, find that user, and show them data that they are suppose to be seeing. My Project table in the database has the column names “title, description, due_date, and user_id”. This means that Users may create projects and give them a all of those attributes to store in the database to save for later. My Task table in the database has the column names “name, description, due_by, user_id, and project_id”. This means that task can also be creating with these attributes. Something I want to explain is, every new User, Project, or Task that is created and stored in the database comes with an id number. Meaning the first User stored in the database will have the id number of 1, the second will have an id of 2 and so on. This id number is referenced when implementing functionality within a rails application. When project is created, it must have a user_id so that we know which user has created this project. When a task is created, it must have a user_id so we know which user created the task, and a project_id so we know which project this task belongs to.

The Models are also where validations and scope methods come into play. One of the validations for my User model looks like this: “validates :name, presence: true”. This line of code means that the a User must be created with the “name” cloumn filled out, otherwise the database will refuse to save the user in the database. These are implemented to prevent false data. For instance, if a user was created without a name or a password, how would we be able to verify that this user is who he/she says they are? We can’t allow a user to be created without us knowing who they are and what they’re doing in our app. We deserve to know!

Scope Methods are another subject, we user scope methods in our Models to reference the data stored in our database in a specific way. For example a simple scope method I used in the Project Models looks like this:

“scope :most_recent, -> { order(“created_at desc”) }”

This method, named “most_recent” will search the database and look for projects in the order of when the projects were created, and return them in a descending order (meaning the most recently created project will be at the top of the list). This is interesting because we are able to manipulate the data we want returned from the database and show it to the user in whatever way we want. A more complex scope method i used was this:

“scope :most_tasks, -> { left_joins(:tasks).group(‘projects.id’).order(‘count(tasks.project_id) desc’) }”

This method, named “most_tasks” implements a “join” query, which joins two models together to implement their data together. This “left_joins” puts the project and task tables together, groups them together by their id of the projects, and puts them in the order in which the count of the tasks project id is highest to lowest. This is very confusing, and took a lot of time to figure out, but if you work your way through it one query at a time, you can break down the data any way you please.

LASTLY, another piece of the User model I implemented was the “has_secure_password” method. This method is used with the Bcrypt gem, and is the reason the column name for password is labeled “password_digest”. What Bcrypt does is, takes the password input from the user and “digests” is in a way that encrypts/filters the password so not even the people running the website can know what their password is, but the database does, so when a user returns to the website and wants to find their username and password the database knows to match the originial version to the encrypted version, allowing access to the users data.

NOW we will move on the the controllers. The controllers are the way we control the data we want to be displayed on the web page. Each model has a controller, along with an application controller and a sessions controller. The controllers all have actions that allows the person using the web app to view and manipulate data. For example, in my Users controller, I have the actions “new, create, and show” These actions give functionality to our website. The new action wil take the user to the sign up page where the user will fill out information for a new user. Once the info is filled out the “create” action will take over and take the filled out info and store that info into the database then redirect the user to the show page that shows info about the user. All this is possible through controllers. When we create a new project, when we edit an existing task, when we log out of the website, all of this is possible through controllers and their action methods

Along with controllers comes routing. The routing system is used to create the urls that represent what data will be show. For example “/projects/new” is route in which the user will be shown a page where they can create a new project. “/tasks/7/edit” will show a page where the user can edit the task with an id of 7. Now, Nested Routing is where it gets tricky. Nested Routing useds the resource method available in Rails that automatically creates the routes for “index, create, new, show, edit, update, destroy” this resouce method then takes it a step further, using the relationships between models to their advantage and creating a more understandable route. Through nested routing we can create a route that looks like this “/projects/3/tasks/7/edit”. This route represents a page in which a task with the id of 7, which belongs to a project with an id of 3, is being edited. This allows a task to be created for a specific project on a page, rather than telling the page which project this task is going to belong to, the page already knows which project this task will belong to. Again, through the power of controllers this is possible, along with Nested Routing.

The views are basically just hmtl pages that show information that has been passed from the models and controllers. The views just reference the info from the models and show the user the info. Views also have forms, which is what a user would fill out when signing up for the website, or editing a project they have created, or typing out a new task. The forms take the information that was filled out and stores it into the databse for later reference (aka logging back into the site or editing a task that you created 3 days ago). Forms are also where partials come into play. For example, on my “/projects/new” page, I will be shown a form in which I will fill out information for a new project. I Fill out the information then realize I have typed in the wrong due date for this project, welp I’ll just go to the edit page and BOOM problem solved. Now, what will be the difference between the form the user will be prompted with when making a new project and the form they’ll be prompted with when editing that project….? Trick question there is no difference! So why not just create a file with the code needed to create a form and then reference that file in both the “new” and “edit” page for the project! Partials make this possible, you can create a form file and reference that file whenever need be. You can do this same with displaying info about the project. You can just create a partial that displays info about the project and reference it on multiple pages such as the index and show pages. Validatio errors can also be shown with partials. You can create a errors file in the layouts folder. This file can reference any validation errors that pop up while creating a new project, task, or user. You can reference this partial so that when an error pops up, the view page will show those errors.

All together, by the end of this project I was satisfied, both with the feeling of completion and accmplishment. I learned a ton throughout creating this project and was very excited to implement my knowledge in my own way. It was a difficult hill to climb, but once I reached the top I was glad I took the journey.

  • Github Repo: https://github.com/eliwines19/task-manager
  • Video Demo: https://drive.google.com/file/d/1B5bYWH4WcH3tr04FElT98G4Ncm6WDY-/view?usp=sharing

Thanks for reading!