Build a Fullstack Rails App: Part One - Overview & Planning
Building a "Pick Names" app with Rails 7 & Hotwire
Intro
This series of posts is intended to walk someone new to Rails and web application development through building a somewhat simple app. What this isn't is a full course, explaining in detail each piece of tech we use, but there still we be some brief explanation of things to help you get familiar with what we are using. I'm assuming at least a bit of familiarity with things like HTML, CSS and a programming language like Ruby. Not that you can't gain some familiarity by working through this, but this isn't a complete introduction to those types of things. Later articles may expound and add features to this same app, for example adding users (authentication), authorization (who can do what), payments (using stripe) etc. As for now we will keep things simple and "lean". This will be an "MVP" (minimum viable product). We will measure viability by saying, you the individual user can start this up on your machine, enter a bunch of peoples names and have each one assigned to another. I'll give more requirements in the "App Requirements" section.
Getting Started & Setup
This also isn't going to spend much time on getting your local environment setup. I will say you will say you will need to do a few things:
Install Ruby (the programming language we will be using)
Install Ruby on Rails (the web framework)
Install Git (version control for our code base)
Optional: Install Postgresql (the database we may use, you can certainly use an alternate one, like SQLite or mysql, but I usually use Postgres), however recently sqlite has been promoted as something we can use in production apps, so I may give that a go.
To accomplish all of these things, will point you towards GoRails.com https://gorails.com/setup/macos/13-ventura for mac
https://gorails.com/setup/windows/11 for windows
https://gorails.com/setup/ubuntu/22.04 for ubuntu
These links will have further navigation to get all set up and also for different versions of those operating systems. GoRails is also an incredible resource for learning Ruby on Rails.
App Requirements - Draw Names
We are going to scratch our own itch, well at least my own itch. Every year around Christmas time, I want to give gifts to my my siblings and they want to give gifts too. But rather than everyone get a cheap, dumb gift for everyone else, it makes sense for each of us to give just one gift to one other sibling so it we can focus on one gift since time and money can be scarce. One solution is to get a few small strips of paper and write everyones name on it and then draw them out of a hat. We don't all live in the same city, so its not always easy to do this together, so someone would do it without us. Then also while doing that, you may end up picking your own name or picking a spouses name. Also, you might end up giving to the same person two years in a row (or you do one year and your spouse the next). We also may or may not want to keep secret who got who. We want to eventually solve all of those problems, but we will not worry about spouses, multiyear tracking and keeping things secret yet. Simply being able to 'draw names from a hat' with a web app, is fine for now. Also, leaving the data schema normal & open to allow for agile adjustments later.
We will need a simple pretty simple experience and interface to accomplish this. In my head I imagine a simple landing page explaining what this will do, and then a button that says start a new name drawing or something to that effect (maybe we call it a 'hat'?). Clicking this will bring you to a page (that you could come back to, remembering what happened before), that has an input box for "Name" a button that then adds it to a list which is on the other side of the page. Underneath that list there is a button that says "Draw Names" which will then take them to a page showing the matchups in some sort of list, like "John -> Jane" and so on. You can navigate back to the previous page from there and see a list with that first result as a hyperlink in a list, and you can still add, edit or delete names from the list and hit the "Draw Names" button again. We won't worry about editing a drawn list (switch who got who) since the whole point of this is to not interfere with the randomness. But who knows, maybe our users will demand this feature later, but I'm of the opinion it shouldn't do this.
Languages & Frameworks Used
I want to give a simple blurb about each piece of 'technology' we will be using. By technology just mean what languages, libraries and frameworks.
Ruby on Rails
Ruby is a programming language. It is what we will be able to programmatically tell our app what to do. Ruby on Rails is a 'framework' intended to reduce the amount of code needed to create a web application with Ruby. It is a collection of 'libraries' focused on being able to get a web app up and running with minimum effort, allowing the developer to focus on the more important things than the mundane things you would do the same over and over again. Ruby on Rails is a true 'fullstack' frame work, meaning it can handle both backend code and frontend code. Apart of the front end there still is going to be html, css and javascript, but with help from Hotwire (Stimulus.js and Turbo), making a dynamic single page application won't be very hard and we won't have to employ an entire complicated framework for the frontend, like React, Angular or Vue.
Hotwire- This is rails way of handling a dynamic front end, with out having to write any crazy spaghetti javascript. It consists primarily of two parts Stimulus & Turbo which work seamlessly with our backend code. Turbo focuses on enabling dynamicly sending "HTML over the wire". Which means the server renders the HTML and then the frontend swaps pieces in and out without needing to either rely on custom or complicated javascript or entire page refreshes (like the old days). Stimulus, from its own github page: "Stimulus is a JavaScript framework with modest ambitions.", which just means we aren't about to embark on a 100 hour learning curve with something like React, but instead for the most part will be writing vanilla javascript in a nice controlled, non-leaky way (I'm looking at you jQuery).
Javascript
Hopefully we will be writing just a little bit of this within the Stimulus framework mentioned above. This is how we will get more dynamic features out of the user experience. Maybe we need to refresh a section on the page by changing a value in a select box. HTML can't handle that on its own since it mostly just knows how to initiate requests via button in a form. But javascript can do that easily. Also behind the scenes javascript will be powering Turbo, lessening the amount of repetitive javascript we will need to write. Not that there is anything wrong with writing javascript.
HTML & ERB
Hyper-text Markup Language is just they way we tell a browser how to structure a page and then CSS will look at the html to decide how to style it. It isn't a programming language, but a templating language. ERB is a 'templating' system for Ruby. In the end it simply means a way to write Ruby code inline with our HTML. For example if we have an array (list) of @drawings, we could do something like:
<body>
<div>
<% @drawings.each do |drawing| %>
<%= link_to drawing, drawing.name %>
</div>
</body>
You can see the html tags like <div> & <body> and then you can see Ruby code after the "<% ... %> and also the "<%= ... %>. The <% indicates this line is Ruby, but not to be rendered to the page. The equal sign indicates this is Ruby code to be rendered to the page. You can see a Rails helper method "link_to" which will generate an anchor tag like <a href"..."></a>, linking to the provided 'drawing' and showing the lists name as the link text. There are other templating systems for Ruby, like HAML and SLIM (which are my favorites) that further speed up development time by reducing the amount of code you have to write. ERB is the default and allows you to write plain HTML so we will stick with it as its important to learn plain HTML before using something like HAML.
CSS
Cascading Style Sheets are the way to tell a web browser how to style the HTML given. You give HTML elements IDs and classes which are then references in the the style sheet (a file with .css as the type). You can actually write styles inline with your html if you desire as well. The cascading part simply refers to the fact that the last styles added would override the above styles. This article isn't focused on teaching CSS, but its incredibly important to know at least the basics of it. But we have a css framework we can use called Bootstrap that will make our work here easier and better looking without much work or in depth knowledge of CSS.
Bootstrap
This is a CSS framework that makes quick work of common elements of CSS, like components, responsiveness, layout, utilities etc. You should still learn CSS as well as you can, but you should also learn to make use of a framework or library like this, as it can speed up development time and many or most apps out there use either bootstrap or something like Tailwind, bulma or others.
Data Modeling
Now that we have the requirements for what this app must do we can start deciding how to architect our database so it can handle all the things we want to do. I won't teach you a full course on relational databases here, but hopefully this will help you get more familiar with them.
From our requirements we can start to pull out some of the tables and concepts we will need to persist and how they will relate. We need something like 'hats' which contain 'names'. We will need a 'drawing' which will be hold a set of 'name_matches'. Commonly it is said among developers that naming things is the hardest part of programming, we could certainly come up with other names, even better, but I think these will suffice.
Here is what I'm imaging these tables and their fields will look like:
table - hats
id:bigint (rails handles this automatically, will be present on all other tables)
created_at:datetime (rails handles this automatically, will be present on all other tables)
updated_at:datetime (rails handles this automatically, will be present on all other tables)
name:string
(we could consider a unique index here to prevent duplicate named hats, but I anticipate we may eventually scope this to a user, but we aren't introducing users yet, so lets leave it open, perhaps add a simple rails model validation for unique names and not constrain our database.)
table - drawings
hat_id:bigint (references hat table), required
name:string, required, not null
unique index on name and hat_id, so people won't get their drawings mixed up.
table - names
hat_id:bigint, references hats table, required
name:string, required, not null
unique index on hat_id & name, so its clear who is who with no repeats.
table - name_matches
drawing_id:bigint (references drawing table), required
name_1_id:bigint (references name table), required
name_2_id:bigint (references name table), required
unique index with name_1_id and name_2_id and drawing_id (don't want to create bad data)
As we go and find new features to add, some of these more sparse tables will receive new fields, but for now this ought to allow for our most simple use case as a reminder is to first: create a hat, which is a form with simply a name. Submitting that form takes us to this new 'hat', which has a few buttons, one is to create drawing (with an auto-generated but editable unique name), which will not be enabled until at least 3 names are added, which have a button for that. We can provide some text to indicate that. Then the drawing button will run an 'algorithm' we write later that will go though each name, pick a random and unchosen name and create a 'name_match' record for each one, tied to that 'drawing'. Users will be able to create as many 'drawings' as they'd like for a give hat with its list of names.
We can see here, that with a solid, concrete idea of how our UI/UX will work, we can start to craft a good database schema. It becomes clear which tables we will need and how they will relate to each other as we start to write out a meta schema like I did above. I didn't have that all in my head before I wrote it out, but I learned more and asked questions, thought of answers as I went to get to that point. We can also start to see some ways to validate our data with unique constraints and required fields. With this small amount of planning we can lay the groundwork for our app.
However I tried to craft this in a way that is open to change, but I don't know everything yet and thats ok as we can later write 'migrations' that can add to and change these tables and fields, and even create new tables. We aren't locked into this schema, allowing us to be agile and improve things as we experiment ourselves and even allow others to use it.
This is just part one in a series of articles of how to create an app using Ruby on Rails, but so far we haven't written any code! It just to show that being able to 'code' is just half the battle here. Part two