Back to Square One

It just goes to show you that you should never be clever with your programming unless you absolutely, positively have to. After I made my pull request to mongoid, I started to tackle the friendship system.

As you may recall I was going to have the User collection relate to itself through a Has and Belongs to Many relationship, one of those neato things that mongoid is capable of. I thought this would mean that there would be an array field on each user document containing his or her friends list. Every time you created a new friendship, both friends would have each others user id in their friend_ids field. You could use both users to reference each other, so you could figure out who they could message, see their profile, and invite to events.

I cribbed from the relationship model in Michael Hartl’s rails tutorial app. But you see, I was going to do something different! I wanted users to only have mutual friendships! I wanted to get rid of the join table so I could have so many less queries on my database.

I thought I already had it working through the tests on the user model. All I had to do was to get the friend and unfriendly buttons working in the view. I was a little unsure of this because the pattern I was using still assumed there was a join table.

So I put it out to The guys in the Fraser Valley Ruby brigade official irc channel. Brian Pearce opted to help me out. We got it to explicitly use the friendship controller to create the relationship.

When all that was done, strange things started to happen. User a would friend user b. User b would show up in user a’s friend list, but user b wouldn’t acknowledge user a as a friend. Just like highschool.

It turns out that habtm relationships have a lot of trouble when working with just one collection. It can’t figure out which direction the relationship is going! Again, just like highschool.

So, I need two arrays. One which describes who the user has friended, and another describing who has the user as a friend. I was working under this pattern before, so I restore it and try it out in the console. It works, but the records aren’t saving! I use the save! Method and find that it can’t save because the users password is missing. Crap!

That means if I’m going to use two arrays, I need to disable the password validation on the user model. But if I do that, a user could replace a password with an invalid value leaving the system completely exposed to hackers. How do I make this work without messing with the model attributes?

My friend Brian presented the solution: use a Join table. That way the direction of the relationships would be kept nice and explicit. Not only that, I could add attribute to the join table to track the status of the relationship, not unlike the status of the invites I was trying to make into a hash field not so long ago.

So after all that angst, I’m right back where I started: using join tables. I’ll have to use them for the invites too, otherwise I’m opening myself for another big mess. I shouldn’t have tried to mess with tried and true methods that would be all but invisible to the user! I should have kept that old relationship model and made it so that only mutual friendships are allowed! I need to save my brain power for when my users are writing gigabytes of data into my servers and producing usage patterns specific to my app! Until then, I need every shortcut, every precooked solution out there to get this app deployed!