(Don’t care about explanations? Scroll down for screenshots and code.)
Over the years, I’ve accumulated a bunch of blog posts, YouTube videos, conference talks and so on, teaching the things I teach — Ruby and Rails programming, building web frameworks, raw coding technique and more.
I want to put these together into longer classes. I’ve tried some obvious ways to do that: email classes, summary blog posts, email newsletter, RSS feed. I am not especially happy with the results. I get complaints that I should have things that, in fact, I do have but they’re not easy to find and consume. In the age of the Internet there is no reason to muddle through an inconvenient, patchy interface to slowly get little bits of content. People pay for my books because it’s nicer to get a big chunk of structured learning, put together well.
I love to build things to find out why they’re a bad idea. Anybody here remember Rails Deploy In An Hour?
Everybody tells you not to build your own content management system or class software. Then they spend an enormous amount of time building a horrible kludged system using third-party software that neither suits their purposes nor keeps working well. But people who did both think that building your own is still a worse idea.
So: I’m going to build an experimental courseware system. If it turns out usable then you (yes, you) will be able to sign up and work through some of my free (and eventually paid?) material, get recommendations and generally treat it like a Udemy-type “learn a bunch of stuff” experience. I may also have looked at the old RailsCasts page and thought, “I wish my stuff were laid out nicely like that.”
But even if I never make something usable, I’ll work through building an open-source Rails app in a series of posts. My plan is to show off interesting Rails features and show you how they’re implemented.
As a sidelight, courseware actually has a lot in common with growth hacking software (aka “like marketing, but with an engineer handy”) — it wants to send email, track progress, show you things similar to what you seemed to like last time and so on. I’ve had a job as engineering support for marketing before, back when I ran an analytics group at OnLive. But this seems like a great chance to show off what this looks like in the small if you’re just one person doing your thing. So there’s likely to be some marketing “how to” bits as I go along.
A Simple Start
I have a few spare domains with cool names sitting around. Don’t we all? I shut down an old project called Ruby Mad Science awhile back and I’ve been itching to reuse the name. So now I have a GitHub repo name.
There are going to be two interesting kinds of data, at least at first.
The first kind is learning resources — videos, blog posts, books and so on. That’s a pretty limited set, tens or hundreds of items for now, maybe up to thousands if this became massively successful. It’s also public information — nothing there should be private or surprising. And it’s going to be pretty freeform. I may want to use a serialised column so that it can change frequently. Could I use Postgres-specific BSON fields and get better data size and indexing? Sure. But this is going to be tiny, I doubt it will want indexing early on, and I’d rather do something generally compatible.
The second kind of data is about learners. There will be ordinary account information (e.g. email address, hashed password) and information about what learning resources are available or have been completed. I’m going to need to be careful how I display this. I have a few thousand people on my email list or who have bought my books and it’s not okay for me to just show their information. So I’ll need some kind of anonymysation to take screenshots. It sounds fun when I think of it that way. I could start with fake data initially. But real data shows interesting problems and that’s a good thing.
The MVP here should be able to let you log in and track completion for one or more series of articles. In other words, it’ll do the same kind of thing as my existing email classes (one for Rebuilding Rails-type content, one for Mastering Software Technique,) but with tracking so people can remember how far they’ve gotten and optionally show off.
I still have no clue how public to make this stuff. Some people would be thrilled to show off progress. Some people want no information revealed about them, ever. I think I can serve both groups pretty easily with a “show off your stuff?” opt-in, but let’s see, shall we?
Let’s Write Some Code
A lot of this planning won’t survive early contact with a prototype, let alone any actual users. Let’s make some code happen and I can start finding mistakes.
Simple stuff: new Rails 6 app, then add Devise, which seems to have switched from platformatec/devise to heartcombo/devise while I wasn’t looking. Seems legit — the ‘devise’ gem on RubyGems.org now shows the heartcombo repo as its homepage.
I ran the Devise generators (“rails generator devise User”, “rails g devise:views”) but otherwise kept Devise’s settings default. I’m sure I’ll tune the app for “easy to show up and just do stuff, prefer login via GitHub or Twitter or something” later. But for now I want a simple app up and running rapidly.
I’m not putting contribution instructions in the README yet. It’s far too early to be a good idea for other folks to submit pull requests. The app is still figuring out what it is, and so I’d have to be rude about rejecting features that don’t match a vision I haven’t even documented. No need for me to be preemptively rude to my friendliest possible contributors! (Also, it’s very rare to get contributions until a thing is up and running okay.)
I’m assuming that to begin, the unit of interesting functionality will be the “topic,” which will be a collection of interesting resources and some way to check them off as a user goes through them. Think of an email class on Rails internals or databases that they work through, or a chapter of Rebuilding Rails.
So I’ve created a quick “topics” controller with “show” and “index” actions, and pointed the root at index.
I run “rails server” just to verify — oh hey, right, Puma is the default server now. That’s lovely. Puma is highly performant and straightforward to use. WEBrick (Ruby’s built-in server) is okay, but not amazing.
There was an announcement of the core Rails team looking for WTFs — places that the Rails 6 experience was broken out of the box. But so far it’s working fine for me. I did have to install some dependencies like Yarn awhile back, but it’s working fine now that I have them.
Now Some Actual Functionality
I go ahead and add “login” and “sign up” links on the right, and just enough links into Devise for me to create a new account. That’s going to be important later.
Great. So, like, this is a perfectly fine “hello, world” app with users but I’d like to get to where I can do something. I think I’m going to start with a “topic” including all the steps in a single JSON blob, though I doubt that’ll be true for long. For that to happen, we need a table to store the JSON blobs.
I generate a Topic model with migration and a single JSON “steps” field. I put together an “index” view and suddenly realise that when choosing a class-or-similar to take, people are going to want some kind of a name or other brief description of it. I haven’t pushed this commit yet, so it’s impossible that anybody else could be using it (also, I’m a team of one) so I just edit that to fix it.
Cool. Time to put to test that HTML for the view. But a table with no rows is just blank, so I surround it with an “if @topics.empty?” to show “No topics!”. It fails, because I’ve never set @topics.
So I pop open topics_controller.rb and look up all the Topics. Pagination can come later. I also look up a topic in show() by params[:id] as well, for good measure.
But still, no topics.
Time to pop into the Rails console and create a couple. Remember that “steps” is a JSON-field, which can contain any JSON-serialisable object.
And with that done, I can hit “reload” on my root (the Topics index page) and see a little ugly table with the objects I just created:
And with that, it’s time to wrap up for this post.
What Happened Again?
In this post, we put together the bare beginning of a Rails site for a learning application. We have an index of topics with JSON-serialised data about what each topic contains. There’s also enough Devise-based user code to create and log in with accounts, and to see if you’re logged in, though nothing is yet protected.
With the simple, bare site as-is, the obvious next steps are to make it prettier (something I definitely want to do!) and to make the Topics more elaborate. It’s important for users to be able to mark sub-steps completed — that’s the first interesting functionality that the app can have. And very soon I’ll need to deploy this thing. So that should all happen in the next few blog posts.
Want to see more? You can check the rubymadscience tag on this blog, including not-yet-published ones. There’s also an RSS feed of posts at the top, or you can subscribe to my email list below. I’ll definitely email the list with these posts.
Or if you’ve bought one of my books, you get to read and discuss blog posts early with my readers as I finish them, in the #prerelease-blog-posts channel of the customer Slack.