A few weeks ago someone on reddit asked if Gamocosm could be used just for the automation, and not Minecraft. As I thought about the best way to implement this feature, I realized that my models were probably backwards, and fixing the structure would require flipping the relations in the database around.

When designing Gamocosm, I first decided to separate the models for data related to the server, and the Minecraft installation. I decided that users will have “Minecrafts”, and each “Minecraft” has a server. It made some sense at that point because I was thinking to primarily support Minecraft, and possibly later allow users to use different hosting providers.

Right now, it makes much more sense that users have servers, and each server has an associated Minecraft object. I’ve also decided that supporting different backends will be less important, as just supporting Digital Ocean keeps things simple and straightforward (Gamocosm is primarily for small, private servers).

Before, a Minecraft object also had ServerLogs, and a Server had a ServerDomain. It was quite awkward. With the current hiearchy, a Server has a domain field, and ServerLogs. Simplifying/making consistent these other models was actually a big reason I was convinced switching things around was better. That the main page (after logging in) is /servers and now handled by the ServerController also makes more sense, and while refactoring I noticed many other things were simplified by having Server be the top model (under User), especially in the background workers.

Migrating the database

So the database used to have tables for users, minecrafts, and servers. Servers had a foreign key to minecrafts, and minecrafts had a foreign key to users. Now I wanted minecrafts to belong to servers, and servers to belong to users. My first idea was that I’d have to create new tables, and load all the data into them. However, I ended up doing a two-part migration:

  1. swapping the fields in minecrafts and servers
  2. renaming the tables

This had the nice benefit of preserving the UUIDs for minecraft/servers. I also did not have to worry about creating new records. It was tricky, as I couldn’t risk breaking or losing users’ data on the production server, but I think the migration worked well.

You can see the two migrations here and here. Both are reversible, as I tested migrating and rolling back on my development server to hopefully iron out any bugs.

I actually did run into an error migrating in production; Rails/Postgresql was complaining something about a duplicate index name on a primary key. Rails does a lot of “magic”, and I did read someone say that rename_table will update the index names. Migrating and rolling back worked fine on my development server (turns out I manually renamed the index earlier while confused). Anyways, it seems like Rails doesn’t automatically rename indexes on primary keys if they are UUIDs, so as you can see in the second migration I do that manually.

Conclusion

Here is the commit where I updated all the application code (and tests) for the new model hiearchy. I think I had to sift through pretty much every single file. Unfortunately, while it seems there have only been a couple very simple bugs (misspelled names), the first prevented a user from adding a friend, and the second caused a crash logging in. Unfortunately, the tests managed to miss them, but at least they’ve been fixed now.