Rails Project: Yarn Stasher
Tags: rails, ruby, webdev
Published: 2021-06-07 21:00:45

Photo by <a href="https://unsplash.com/@mkvandergriff?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Maranda Vandergriff</a> on <a href="https://unsplash.com/s/photos/yarn?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>

This week I finished up my third project for the Software Engineering course at Flatiron School. The task was to create a Rails webapp with at least one join table/model, some scope methods, validations, vanilla login/signup, oauth login/signup, at least one nested resource, and display of validation errors. 

For the previous section of the course, I had created a basic CRUD app using Sinatra that allowed users to keep track of their yarn stash. My hobby is spinning and knitting, so this is something I would use, and also something I can't find an existing solution for. And having come up empty on new project ideas, I decided to just build on my initial idea by adding the ability to create projects, assign yarns to a project, and leave comments on your own or others' projects.

The first thing I did was spend about a week stressing over how to set up my models and migrations so that my project would meet the requirements without too much re-migrating later. I made a wireframe (after watching several videos on how to make a wireframe with Chen notation), and that helped me visualize what I needed to do. I went a step further and hand-drew a bunch of 2 inch squares on printer paper (because I felt like I was wasting time trying to figure out Canva or Figma) for each view I would need and what links were needed on what pages for navigation, where I would need validations, and what I wanted the basic layout to look like. 

Finally confident that I understood what I needed to do, I used the resource generator to set up the framework for my app. I added some basic validations and generated some seed data to play with. This also allowed me to play with my models to understand how they would work together given the associations I assigned them. Since I am using Rails 6.0, I followed the documentation, since some commands are different from the ones I had been using during lessons and labs. The biggest difference is running `rails routes` instead of `rake routes`. I spent some time testing out the associations in the console to make sure I knew how they worked. 

The next thing I worked on was adding the vanilla login/signup/logout functionality. This was very similar to Sinatra, and didn't give me too much trouble. Hint: Make sure your bcrypt gem is un-commented in your gemfile before starting this part :) I also added a navigation bar to the application layout file to make it easier to get around while testing my app in the browser. I ended up changing this from my original plan because what made sense on paper did not necessarily make sense in the browser. I also added flash messages to display signup/login errors to the user in the views. 

With the login/logout functionality in place, I began working on create forms and views. I decided to nest the comments resources for index, new, create, and show actions under the projects resource. This made sense to me since all of the comments can't exist without a project. I did have to pause here and refresh my knowledge on nested routes, since I only half-understood it the first time I went through the lessons. The actions in the Comments controller took me awhile to figure out, because the new and create actions required the use of build methods, and I had to spend time trying to understand how they work and what they return. 

With the necessary CRUD actions created for all of the models, I moved on to some error handling. I made an error partial and then added a line of code to render it on each page if there was an error present. I added a nested form to the Create Yarn page to allow a user to also add a new project when they add a new yarn to their stash, and then I had to do a little googling to figure out how to make filling out that nested form optional. I also added an optional collection select to the form to allow the user to associate a new yarn with an existing project. 

One thing I had been dreading doing was figuring out scope methods. I don't think they were covered in the curriculum, but I had read about them in the Active Record documentation. So I re-read that section, and then found a lecture recording that covered the topic. I ended up with three scope methods, which display data about what's going on in the app on the post-login landing page. In the Project model, I have a scope method for finding the project with the highest number of comments: 

```
scope :popular_project, -> { joins(:comments).group(:project_id).order('COUNT(comments.id) DESC').limit(1) }
```

And another one for finding the 5 most recently created projects:

```
scope :recent_projects, -> { order(created_at: :desc).limit(5) }
```

I ran into some trouble getting the scope methods to return what I wanted them to. I kept getting 'undefined method for ActiveRecord_Relation' errors. It took me a couple of hours to figure out that I needed to either iterate over the array that my scope methods were returning, or call an array method on them, like `.first`, to get them to return the actual objects rather than an Active Record Relation object. 

More confident now, I added a bonus scope method to my Yarn model:

```
scope :popular_yarn, -> { group(:brand_name).select(:brand_name).order("count(id) desc").limit(1) }
```

This one returns the brand_name attribute that occurs most often in the database. 

Scope methods conquered, I moved on to adding some before actions to require that only the users who made a thing are able to edit or delete it. So only the user who created a yarn can edit it or delete it, but any user can view it. I also made the data displayed on a user's profile page dependent on the id in the URL so that a user can view other users's profile pages to see their yarns or view their projects. I took the extra step of adding a tiny bit of logic to the views to hide the links to the edit and delete actions unless the session user_id matches the user_id associated to the object in question. 

Finally, I pulled some of the styling from by Sinatra project and applied it to the Rails version. I used CSS grid to arrange project links as cards on the post-login landing page and the user's profile page, added a footer, and styled the nav bar. 

To meet the final requirement I had remaining, I tackled adding OAuth login. I tried Facebook first, but got frustrated with it and switched over to Google. I thought I had set everything up correctly, and I was feeling confident because this was one part of the Rails curriculum that I hadn't struggled with :) But my hubris came back to bite me, because it didn't work and the reason was because I had misspelled GOOGLE in the .env file. It took me 2 hours to see that spelling error. BUT at least I remembered to add the .env file to my gitignore, so I had that going for me. 

I am almost ready to turn this in and move on to the JavaScript section of the course (finally!), but I have a couple of UX related changes I want to make before I'm totally happy with the state of the project. I am sure I will come back to this project in the future. I would love to be happy enough with it to put it out in the world, but it needs some JavaScript magic to make it as I envisioned it. 

Here's the link to the repo, if anyone is interested:
https://github.com/jrrohrer/yarn-stasher-rails

Thanks for reading! Wish me luck on my assessment!