App Academy: Week 5, Day 2
Today was a pretty big day at App Academy. Our project was to create Rails Lite, a lite version of Rails that includes a Router, a ControllerBase class with which to write controllers, and logic within ControllerBase to render .erb views, redirect the client to other pages on the app, and set the session cookie. All of this was written in conjunction with Rail's Rack class, which provides us with Request and Response classes. To use these classes, we first start a Rack server with Rack::Server.start and pass in our app along with the port through which we want to be able to connect to it. Then, within our app, we can pass Rack::Request.new the env object provided by Rack::Server.start, which creates a Request object on which we can call methods to determine the contents of the client's request. Then, through the internal logic of our app, we build up a Rack::Response object, which we finally call .finish on when we are ready to respond to the client.
After finishing up the required sections of the Rails Lite project, I moved on to the bonuses, where I implemented flash and an ExceptionCatcher middleware. In Rails, flash is a method within controller with which we can access and set key-value pairs within the client's cookie that will persist only through the next response cycle. Thus, if I write flash[:errors] = "Bad stuff" in one of my controller actions, when that action is executed, flash[:errors] will still return "Bad stuff" during the next response cycle, but will be nil thereafter (unless it is set again, of course). To implement this functionality, I set a flash cookie on the client, which I stored as a hash serialized to JSON. Then, when a controller calls flash for the first time during a response cycle, it sets a @flash instance variable to the deserialized values of that cookie.
However, Rails also has a flash.now method, which works just like flash, except that key-value pairs set with it will only persist during the current response cycle, and will be gone by the next cycle. To implement this functionality, my Flash class sets an instance variable @flash_now to true whenever .now is called on it, which causes it to temporarily respond to any methods immediately called on it by using instance variables, rather than the values store in the cookie. Then, @flash_now is set back to false, causing all further calls to flash to function appropriately.
ExceptionCatcher is a middleware that I wrote which displays the stack trace, error message, and a preview of any error-throwing code in the app. To integrate this middleware into my app, I used Rack::Builder to add ExceptionCatcher to the top of my middleware stack. Internally, ExceptionCatcher catches any error thrown by the call to the next piece of middleware or app down the middeware stack (and thus any error produced by anything further down the stack that isn't caught). ExceptionCatcher gets the error message and stack trace from the error object itself, and then finds the code responsible for the error by using a regular expression to pull out the file path and code line from the first line of the stack trace and then loading the appropriate file and parsing the corresponding line. Then, a .erb template displaying all three elements is rendered to the client.