Scripts on Scripts, Code on Code, Ruby on Rails

Abdelrahman Elsirafy
5 min readAug 9, 2021

A piece of advice of I came across some time ago while preparing for my journey to enroll in a coding bootcamp was to practice something known as “tooling” or “scripting”. At the the time, I understood it in a general sense of automating tasks, or pretty much just writing code that you can later use to do things for you. Although I wasn’t wrong, I had yet to learn the real depth that comes with scripting. Ruby itself is a scripting language based on the programming language “C”, and here I was thinking “so this is what low-programming is”(HAH!). Still with that considered, Ruby isn’t even the main point of this article. In fact, it’s Rails and the process of building a web applicaton with what felt like endless documentation and really powerful tools to implement. Something worth noting though is how Rails doesn’t classify as a scripting language. Although written in Ruby (and a lot of it), it serves as a default-structured MVC framework for building web applications that’s also incredibly helpful when it comes to creating, updating, and managing an app’s database.

The third phase of our school’s curriculum was focused on how Rails pretty much bridges the gap between Ruby and full-stack web development. The overall focus of our project’s app in the end was to Rails in managing related data through complex forms and RESTful routes. Ironically, in a struggle to come up with ideas for my project, I decided to go with a project idea builder where users could create a project based on any idea that came to mind, add features or attributes to that project, while other users that took an interest in it could contribute to it and vice versa. With models being starting point for any web app, the first thing that came to mind is to what extent do a user’s ability go when it comes to a project that isn’t theirs yet contributing potentially valuable properties that are. Between the users’ relationships amongst one another, the collective projects within the community of users, and the indefinite features that a project could have, I found myself lost time and time again questioning the projects structure altogether and honestly how much I actually knew or learned throughout this phase.

It wasn’t long before I came to see a pattern where joins between two tables almost always happened at the “child-most” attribute and the main example helping me come to that understanding was the visual example on guides.rubyonrails.org referring to physicians, patients, and appointments. It was how in real-world terms, the least “responsible”(non-parenting) of the three models was appointments and should at least be responsible to track its physician and its patient (since it “has_many” of nothing, it can only “belong_to” something). It can be easy attempting to think like a computer by default when you’re trying to make your code work but sometimes all you have to do is take a moment to think like a human. What throws you off though is how you actually have to build out your models in the reverse order of that same logic. In my app’s case, a user has many projects (whether creating one or contributing features to another’s) and a project has many users through its features.

With that in place, it was time to worry about the real headache. Establishing associations for how data will be effectively stored or whether it’s the right way feels like the human version of recursion. It’s solution depends on a solution; how you plan on querying your database to return the right values, where you want to call those queries while still following the single-responsibility principle, etc. How should I be calling on a user’s projects or a projects users? How am I segregating the owner of a project when they also have many projects they don’t own, all without them editing or persisting bad data or duplicates to the database? My favorite and worst ‘rails roadblock’ was establishing a user’s partners. At this point I’d figured that every user who creates a project should be it’s foreign key “owner_id” under a project’s attributes and the timestamps created by default through Rails could track and show when a feature or project was created. Considering the nature of my app, although it can be an “open community” of people coming up with ideas or bulding on those of others, people actively working on a project you’ve come up with and are invested in is an important part of the app’s purpose. It emphasizes flexibility in being a resource but also the growth for potential success through teamwork. However, what I was looking for was an association between instances of the same model, one somehow parenting others. Let’s say “user A” creates a project , “user B” and “user C” contribute to it, so “user A”should be the parent to “user B” and “user C” given they’re just contributors and “user A” is the owner. Additionally, the users or “partners” I’m trying to return from the database are instances that belong to a project’s feature, not to a project. So technically what I was trying to return do was an association within an association and sadly Rails isn’t THAT nice.

It didn’t mean I was out of options though. In fact the real takeaway that came through a generous amount of reading and familiarizing with what Rails does behind the scenes is how there wasn’t ever a right way for me to accomplish what I was looking for as there were tons of ways to do so. More so, thanks to Rails’ convention-over-configuration paradigm, the amount of tools at your finger tips (no pun intended) only really leaves you with the question of preference to achieve what you’re looking for with some guidelines to follow. In my case, I was looking for “self join” the whole time and it was only a matter of how long it took me to stumble across its documentation. As guides.rubyonrails.org stated,

“In designing a data model, you will sometimes find a model that should have a relation to itself. For example, you may want to store all employees in a single database model, but be able to trace relationships such as between manager and subordinates. This situation can be modeled with self-joining associations:” (provides code for it’s implementation), yet there I was hung up on polymorphic associations thinking it was my best bet.

Everything aside, I tried to keep in mind that a major part in building this app with rails was to use it’s resources effectively yet efficiently. When done properly there’s not much needed from our end as we can let it manage the general flow of data for us by retrieving values through associations or relationships that we define and properly set up in our models. That way you can maintain a database and overall web app with clean non repetitive code a lot of which was prewritten for us. In a lot of ways it’s a strong representation of why software, let alone our extremely technological world, has been and is able to evolve so rapidly. It’s truly inspiring, and frankly one of the very few forms of coexistence that actually makes sense to me. We’re only ever looking forward for the sake of progress as a means for the people after us to push boundaries even further than we could've ever imagined.

--

--