Tuesday, July 18
The Longest Tease
Refactoring Rails has been hosting a "coming soon" banner for nine months since its announcement. Come on, people. It's time to deliver that baby. I can only be enticed for so long. For the love of all things holy, throw us a bone here!
Sunday, July 16
Foreign Keys in Rails in Three Easy Steps
1. Fix Your Migrations
The first thing you need to do is add the foreign key declarations to your migrations. There are several ways to do this. If you want to go old-school, you can hack the SQL directly into the migration file, but if you want to take a more classy (and DRY) route, I recommend Simon Harris' plug-in. The plug-in is very clever about figuring out the relationships automagically, but if necessary you can easily nudge it in the right direction.
2. Fix Your Fixtures
By default, Rails is going to load your fixtures alphabetically, and unless by some miracle that happens to be the correct order in which to load them without violating any referential integrity, you're out of luck. If you use Simon's plug-in, fixtures aren't going to present too much of a problem because it is smart enough to not apply foreign keys to the testing database. However, if you are like me, you're going to write some unit tests to ensure that the foreign keys are intact and operational, and all of those tests are going to fail. But don't fret. Again, there are a couple ways to solve this. The classiest of which is a little code hacking which lets you specify the order in which your fixtures should be loaded. (Will somebody please refactor this into a plug-in already!?) But if you want to go old-school and get your hands dirty, you can simply rename your fixture files, prefixing them with numerical values which coax Rails to load them in the correct order.
3. Fix Your Code
Rails and referential integrity don't always play nice together, so you're going to have to do a little massaging with your code. As I've ranted about here a few times before, one of the most frustrating is the way has_many handles the breaking of relationships. When you "delete" a relationship, Rails doesn't delete the record in the database, it simply nullifies one of the foreign keys, leaving an orphaned record. DHH noted in a response to one of my earlier rants that the reason for this is so the record can be reassigned, thus resetting the just-broken foreign key. However, if that happens to be a real foreign key in a database that enforces referential integrity, you're going to get a barf as the database will not let Rails set it to null. So, instead of deleting a relationship from a collection, you'll need to destroy the relationship itself. A minor syntactical semantic, but confusing and sometimes confounding nonetheless.
Conclusion
That's it in a nutshell. It's a bit of work to overcome a few little bumps in the road, and although it somewhat violates the Rails philosophy of database design, I think it's well worth it, and many of my colleagues tend to agree. As a shameless self promotion, note that I have whipped up a very crude plug-in to make has_many collections behave a little more intuitively (by my personal definition of intuition, of course) -- it should be backwards compatible so dropping it into your project shouldn't break anything.
The first thing you need to do is add the foreign key declarations to your migrations. There are several ways to do this. If you want to go old-school, you can hack the SQL directly into the migration file, but if you want to take a more classy (and DRY) route, I recommend Simon Harris' plug-in. The plug-in is very clever about figuring out the relationships automagically, but if necessary you can easily nudge it in the right direction.
2. Fix Your Fixtures
By default, Rails is going to load your fixtures alphabetically, and unless by some miracle that happens to be the correct order in which to load them without violating any referential integrity, you're out of luck. If you use Simon's plug-in, fixtures aren't going to present too much of a problem because it is smart enough to not apply foreign keys to the testing database. However, if you are like me, you're going to write some unit tests to ensure that the foreign keys are intact and operational, and all of those tests are going to fail. But don't fret. Again, there are a couple ways to solve this. The classiest of which is a little code hacking which lets you specify the order in which your fixtures should be loaded. (Will somebody please refactor this into a plug-in already!?) But if you want to go old-school and get your hands dirty, you can simply rename your fixture files, prefixing them with numerical values which coax Rails to load them in the correct order.
3. Fix Your Code
Rails and referential integrity don't always play nice together, so you're going to have to do a little massaging with your code. As I've ranted about here a few times before, one of the most frustrating is the way has_many handles the breaking of relationships. When you "delete" a relationship, Rails doesn't delete the record in the database, it simply nullifies one of the foreign keys, leaving an orphaned record. DHH noted in a response to one of my earlier rants that the reason for this is so the record can be reassigned, thus resetting the just-broken foreign key. However, if that happens to be a real foreign key in a database that enforces referential integrity, you're going to get a barf as the database will not let Rails set it to null. So, instead of deleting a relationship from a collection, you'll need to destroy the relationship itself. A minor syntactical semantic, but confusing and sometimes confounding nonetheless.
Conclusion
That's it in a nutshell. It's a bit of work to overcome a few little bumps in the road, and although it somewhat violates the Rails philosophy of database design, I think it's well worth it, and many of my colleagues tend to agree. As a shameless self promotion, note that I have whipped up a very crude plug-in to make has_many collections behave a little more intuitively (by my personal definition of intuition, of course) -- it should be backwards compatible so dropping it into your project shouldn't break anything.
Sunday, July 9
Monday, July 3
OpenVPN is Da Bomb
Long story short, last winter our hosting provider (which happens to be the most incompetent company I've dealt with in the last decade; oh the stories I could tell) migrated our fully-managed system to their shiny new and improved facility, and in the process finagled a renegotiation of our contract which omitted a lot of the services that had been "standard" beforehand, like the virtual private network between our office and our servers.
When this oversight was brought to the attention of the paper pushers and check signers, our hosting provider explained to us that they'd be happy to provide the service to us for a mere few thousand dollars a month over our existing service charge. Now, you have to understand that we're a B2B company, and some of our clients are very finicky about security, and commonly audit the way we run our shop to make sure we don't represent a chink in their armor, so having a VPN is critical to our business. But, we're a small company, and that's a pretty large bite out of our bottom line, so we started looking at alternatives.
The first one we checked out was Hamachi. Hamachi is beautifully simplistic, but so simple that it lacked two critical features. First of all, it didn't run as a service, and thus stopped as soon as you logged out of the machine, and Heaven forbid your remote machine rebooted on you and you couldn't get back to it. Secondly, Windows Remote Desktop (a.k.a. Terminal Services) doesn't work over it. That last one is mind boggling.
So we next tried out OpenVPN. Not only did it have the two important features Hamachi lacked, but it also has a neat little trick that lets your connection act as if it's part of the remote network, acquiring an internal LAN IP address from the DHCP server and all. Everything works seamlessly: remote desktop, networked file shares, source control access, etc. I haven't tried, but I bet the printers work as well. On top of that, it handles multiple networks without breaking a sweat. I've got a VPN to my office, one to my production servers, and another to my personal server. Even as I bounce between the network cable to the wifi to dial-up, the service is able to reconnect and reconfigure itself. I've even been surprised by one cool side effect where I closed my laptop (putting it in sleep mode) while leaving a remote terminal open, then opening it back up when I got home and finding the terminal session still alive and kicking.
But -- there's always a but, isn't there? -- we had to pretty quickly remove OpenVPN from our production servers as it was causing a horrible periodic stalling of network traffic. Essentially, every ten minutes or so, the server would just cease to respond to network requests (HTTP requests were the most evident -- we serve about twelve per second). Then, after about one minute of not responding, it would suddenly burst back alive, handling any of the stalled network connections that hadn't timed out. This made our web-site unusable. Note that the HTTP traffic wasn't being served over the OpenVPN connection, nor was OpenVPN even active, it was just installed -- which seems to suggest to me it's a weird Windows driver issue, but I'm not the expert. Unfortunately, the experts can't or won't help as the ticket we opened has gone ignored.
When this oversight was brought to the attention of the paper pushers and check signers, our hosting provider explained to us that they'd be happy to provide the service to us for a mere few thousand dollars a month over our existing service charge. Now, you have to understand that we're a B2B company, and some of our clients are very finicky about security, and commonly audit the way we run our shop to make sure we don't represent a chink in their armor, so having a VPN is critical to our business. But, we're a small company, and that's a pretty large bite out of our bottom line, so we started looking at alternatives.
The first one we checked out was Hamachi. Hamachi is beautifully simplistic, but so simple that it lacked two critical features. First of all, it didn't run as a service, and thus stopped as soon as you logged out of the machine, and Heaven forbid your remote machine rebooted on you and you couldn't get back to it. Secondly, Windows Remote Desktop (a.k.a. Terminal Services) doesn't work over it. That last one is mind boggling.
So we next tried out OpenVPN. Not only did it have the two important features Hamachi lacked, but it also has a neat little trick that lets your connection act as if it's part of the remote network, acquiring an internal LAN IP address from the DHCP server and all. Everything works seamlessly: remote desktop, networked file shares, source control access, etc. I haven't tried, but I bet the printers work as well. On top of that, it handles multiple networks without breaking a sweat. I've got a VPN to my office, one to my production servers, and another to my personal server. Even as I bounce between the network cable to the wifi to dial-up, the service is able to reconnect and reconfigure itself. I've even been surprised by one cool side effect where I closed my laptop (putting it in sleep mode) while leaving a remote terminal open, then opening it back up when I got home and finding the terminal session still alive and kicking.
But -- there's always a but, isn't there? -- we had to pretty quickly remove OpenVPN from our production servers as it was causing a horrible periodic stalling of network traffic. Essentially, every ten minutes or so, the server would just cease to respond to network requests (HTTP requests were the most evident -- we serve about twelve per second). Then, after about one minute of not responding, it would suddenly burst back alive, handling any of the stalled network connections that hadn't timed out. This made our web-site unusable. Note that the HTTP traffic wasn't being served over the OpenVPN connection, nor was OpenVPN even active, it was just installed -- which seems to suggest to me it's a weird Windows driver issue, but I'm not the expert. Unfortunately, the experts can't or won't help as the ticket we opened has gone ignored.
Subscribe to:
Posts (Atom)