Unsolicited Advice After My First Rails Project
Tags: rails, ruby, webdev
Published: 2021-03-25 21:28:54

If you've seen any of my other posts, you might know that I'm doing the full-time Software Engineering (really Web Dev) bootcamp at [Flatiron School](https://flatironschool.com/). We've been building up to Rails for a couple months now, and we finally got our first crack at building a Rails app completely on our own. For my final project I chose to build a site for tracking allergies and dietary restrictions in schools (for use by teachers taking field trips, cafeterias with students that have nut allergies, etc.). If you're interested, or have any advice, feel free to check that out [here](https://github.com/cole-flournoy/rails-student-allergies). 

So let's get into it. These are four things I would go back and tell my past self to save a lot of time and headache building my first project with Rails. I won't claim to have the perfect list for the most common issues, but hopefully I can at least help y'all avoid some frustration in these particular areas.

## (1) Use A Sandbox

There are specific sandbox services or full virtual environments that programmers use, particularly for security reasons, but all I mean by a sandbox here is a place to play around and test code. That can be as simple as creating a second Rails app with the same structure as your main project.       
![sandbox project picture](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ngyss0uwpfcaqqh702x.png)
This is especially useful for sorting out the associations between models and testing out database seeds. If you're starting with only a few basic has-many/belongs-to relationships, maybe it's straightforward enough to skip a test project, but as the relationships get more and more complex, I can't recommend a tester pancake enough. When I haven't used a sandbox in the past, I've ended up accidentally committing a bunch of changes back and forth in the beginning of my project, thinking I had it all figured out before I did. It helps keep your main project code way cleaner by replicating only what worked and was well-tested in the sandbox, and it gives you an isolated, identically-structured database to go back to if you want to try something out as the project progresses.

## (2) Name Your Join Table    

In any many-to-many relationship, you'll need a join table (more on ActiveRecord Associations [here](https://guides.rubyonrails.org/association_basics.html)). But why is this

```ruby
class Assignment < ActiveRecord::Base
  belongs_to :programmer  # foreign key - programmer_id
  belongs_to :project     # foreign key - project_id
end
class Programmer < ActiveRecord::Base
  has_many :assignments
  has_many :projects, through: :assignments
end
class Project < ActiveRecord::Base
  has_many :assignments
  has_many :programmers, through: :assignments
end
```
better than this?

```ruby
class Programmer < ActiveRecord::Base
  has_and_belongs_to_many :projects       # foreign keys in the join table
end
class Project < ActiveRecord::Base
  has_and_belongs_to_many :programmers    # foreign keys in the join table
end
```
What gives? I thought as programmers we were supposed to value our time and always go for the easiest, most concise code possible? Yes, while the second option is cleaner looking and takes half the code, it's also significantly less flexible (and speaking as a beginner in Rails, potentially a lot more confusing). 

First off, it doesn't allow us to work with the join table in any way. Since we don't have a model for it, we don't have the option to add any attributes or validations to it later if we want. And maybe that's just fine for your use case. Using `has_and_belongs_to_many` and creating the corresponding join table in a migration is a perfectly legitimate option, but for beginners I'd recommend starting with `has_many_through`. Experienced programmers probably will have a better idea of their end product when they're setting everything up initially, but for me at this stage it's still pretty common to think halfway through a project "Oh, of course I should have added 'x' attribute to my join table". Starting my projects with `has_many_through` relationships gives me the flexibility to just add a single migration with the attribute I missed, rather than rolling back my entire database and changing all the models.       

Ok, so if we're going to associate our models with `has_many_through` why not just use a standard join table name (for example, `programmers_projects`? Again, you totally can, it's just not as clear. Rails is great; it has so many things built into it that do magic for programmers and make our lives easier. But that Rails magic relies a lot on, among other things, naming conventions. Like many parts of the framework, Rails expects join tables' names and filenames to have a particular word order and pluralization. I would go back and forth a lot between `programmer_projects` vs `programmers_projects` vs `projects_programmers`, etc. trying to figure out the problem before I finally just named my join table something else entirely.

## (3) Don't Rely Too Much On Your Sandbox

Ok, so I know the very first thing I said was 'Use A Sandbox', but just like with anything else, there's a limit. Having a test project to get started cleanly and try stuff out is one thing, but depending on it so much that every time you make a change you try it there first is obviously too much. It doesn't even have to be that extreme. 

For example, I wanted my users to be able to log in through Google, but I was having trouble getting [Omniauth](https://github.com/omniauth/omniauth) to work properly. Maybe it was interacting weirdly with some other part of my code and having a more simplified set up that looks the same would make it easier to spot the bad interaction, or maybe I just needed to start fresh because I missed something in the setup. Either way, perfect candidate for the sandbox! But even when I got it figured out there, I still couldn't get it to transfer over to my real project... 

I spent *way* too long trolling Google and Stack Overflow for answers about what could be interfering with Omniauth (and commenting out different parts of my code), only to find that I had copied all but one gem into my real project's Gemfile from the sandbox. And Omniauth was working just fine! 

WOW! -- SUPER IRRITATING!          

As programmers, we want to keep our code as DRY (Don't Repeat Yourself) as possible, and the same principle applies here. It's not just about efficiency (although typing *every* new thing into a sandbox before you add it to your project does eat up a lot of extra time); it's mostly about protecting yourself from stupid mistakes like I made. The more times you type the same code in different places, the more likely you are to overlook something or make a mistake. So be careful with your sandboxes!

## (4) Write Some Janky Code

Rails has a ton of crazy useful tools to make programming faster and easier. Trust me, I spent a *lot* of time during my project on [this](https://guides.rubyonrails.org/form_helpers.html) page trying to leverage the power of Form Helpers. But sometimes there can be a little too much Rails magic. If you're a student like me, you probably learned and practiced a lot with these helper methods and not a lot with building out similar things yourself. Of course, why would we do it the slow, hard way when there's a fast, easy way?? Well, those helpers are made to solve the most common problems, so what happens when you run into an uncommon problem?   

My advice while you're learning, especially with form helpers but across the board, is to get as comfortable as possible throwing out the magic and learning how the common stuff works behind the scenes a bit more. I ended up spending a lot of time searching for syntax solutions to try to make a more complex set of associations work with form helpers in the way I learned them, when really they were problems that could probably have been solved a different way with 10-15min of creative thinking. 

It's really tempting to always go for the most abstract option ("How do I simplify this as much as possible and let Rails magic do the work for me"), but my experience so far has been that just because it's the 'easiest' solution or a really common problem that Rails has built in a method for, doesn't mean it's the right solution for your project (or that it'll save you any time). This project is the most creative and adaptable that I've had to be as a programmer, and I was most successful when I was willing to have it look ugly for a while and just make it work. Code that works is better than code that looks clean and concise but doesn't work. We'll always look back on old code and be embarrassed about how we used to do things, but the shortcuts are easier to use correctly if you spend time on the fundamentals.  

--------------------------
That's probably enough unsolicited advice for now. If anyone wants to check out my janky code to see if you should even listen to a word I say, the link to the repo is up at the top (also, feel free to watch the walk through [video](https://youtu.be/rCBmG-wHdQQ)). Thanks for reading, and happy coding!