Yes, life ain’t the party it used to be. Gone are the late nights of clubbing and replaced are the quiet country nights of sitting at home and… and… well… trying to find anything to do.
Since the wife is in graduate school and spends every free hour studying (read: this means she has little to no “free” hours), I decided, about five minutes ago, that this Saturday night would be different. It is 7:35 PM. (I guess I decided at 7:30PM) She said she would have to study until midnight. I have decided to conduct a little experiement of my own. I have 4.5 hours to design a web application, implement it, and document both the application at the process. What you are reading is the documentation of the process.
I recently took the Ruby on Rails Todo List tutorial. Ruby on Rails is definitely an awesome web application framework (I hate these buzzwords and titles too, but to steal from MTV, I’d call the name “buzz worthy”). Rails will be my tool of choice for my mission. The mission: Write a web application book reader for reading titles from Project Gutenberg.
I’m off to write the specs.
Time: 7:50 pm
Book Reader specification
Installation – not sure, because not sure what ruby on rails is capable of, handle this at another time.
The main page should give a menu allowing selection of a reading list, current reading, and past reading.
The reading list is a list of books to be read. A browse system for finding books in Gutenberg library should allow books to be added to the reading list.
Books being read and past reading should have multiple bookmarks. There can be 3 types of bookmarks. First is the primary bookmark, this is where teh user left off reading. Second is dogears, this is for points in teh book that are intersting that the user may wish to return to. Third is highlight, these are really just like dog ears, but different types of users may work, think, and feel differently about their books. Highlighs highlight text for easy finding later.
The next set of features probably won’t get implemented immediately, they are teh stage 2 features: Allow preferences for reading books by paragraphs per page (to speed load times), chapter views, and an RSS view. The RSS view oculd be a chapter or number of paragraphs every N days and RSS would be generated for that number of paragraphs or chapters in such increments. Reading the book now becomes as simple as subscribing to the RSS feed.
Stage 2 backend:
Try various gutenberg mirrors in parallel, allow selecting a prefered mirror. Specify a limited local book cache size.
Rails is an MVC, so expanding the above gives natural models for ReadingList, Library, Reading, and Books. Past and Current Reading are really just cases of Reading with a simple boolean switch indicating that the user is done with this Bok.
Properties of Books should come from Gutenberg, so use natural properties for thier publication.
Time to fill up the coffee cup, and check the bread (I’m baking bread while I do this too).
Coffee cold already. I’ve laid out some tables. I’ll need to parse GUTINDEX.ALL and populate the database with its results. I can do this outside the web application.
I’m getting distracted a bit right now. The first loaf of bread goes into the oven in about 15 minutes. The second loaf about 30 minutes after that. I probably shouldn’t be multi tasking while trying to program. Oh Well, at some point I’m going to clean the tub and take a shower too. I’m aiming for that to be my 10pm 1/2 time break.
The tables are going to look like this: (in psuedo schema)
GUTINDEXProperties: –e.g. (full)Title, Subtitle, Editor, Language, Illustrator
GUTINDEX_id int, –fk
# parse GUTINDEX.ALL to populate these tables.
BookStatus varchar(100), — in ReadingList, CurrentReading, Past Read
User_id int, –pk
PrimaryBookmark int, –an offset?
BookMarkTypeName varchar(100), — in Primary, DogEar, Highlight
BookMark int –an offset?
Off to put that into real PostgreSQL DDL.
On second thought I should normalize Authors out of GutIndex. Author is now a foreign key to an Authors table. Now if we want to keep details about Authors, that is a little easier. I will not handle the case of books having multiple authors at this time. For now, Authors will be listed in the Authors table again if they published a book with another author. e.g.:
Joe Blow – The Hard Knock Life
Joe Blow and Terry Harry Berry – The Knock ‘Em Hard Guys.
It would be nice to have an N-to-N relationship between books and authors, but for right now, I will only have a N-1 relationship, so Joe Blow and Terry Harry Berry will be an entry in the Authors table separate from Joe Blow. This will make parsing GUTINDEX.ALL easier for now.
I’m alsmost done with the DDL. I’m just looking up how to switch users and databases in PostgreSQL. The first loaf of bread went into the oven. I forgot to preheat, that is why it is going in so late. Next loaf goes in at 9pm.
First loaf is out, and I’m stuck with not being a DBA. I’m dealing with some PostgreSQL permissions because I want to do things right with a DB Owner user for the DB piece. I’m also dealing a bit with case issues in rails. Apparently if you generate a model or controller with uppercase letters, rails changes them to lower case, but separates them with an underscore, so BookStatus became book_status. Whatever OR mapping Rails does then proceeded to look for a table called book_status, but my table is called bookstatus. PostgreSQL table names are not case sensitive, so even though in my pretty looking definition I call it BookStatus, a listing of database objects reveals all lowercase names. Same is true for PostgreSQL users, databases, and probably all objects, so configurating password auth took more time than it should have. I’m not sure why PostgreSQL doesn’t just lower() everything. Ignoring my lines in pg_hba.conf because of upper case characters was a bummer. Not being able to login with an username containing upper case characters was also a bummer. I should mention I’m using PostgreSQL 7.4 because it is what I happen to have on my Ubuntu Breezy (pre-release) system.
Back to hammering out the PostgreSQL permission issues. Seems like I go through this every time.
Ugh, I just found Really Getting Started In Rails where it mentions specific rules for naming things. All Primary Key columns in my tables should be named “id”, and foreign key columns should be named tablename_id. That is fine, its just not what I prefer. I’ll go change my column names.
I’m still not quiet sure how to model the concept of Users with ruby. I’m leaning toward having a Users controller which assumes a Default User and using that user until a visitor logs in by accessing a Users/login target. Hopefully I can find a good example.
Time to cut the bread. It smells delicious and Janice (my wife) keeps asking if it is ready.
I did some database redesign after reading more rails docs. ClassMethods for Associations is important stuff.
I’m getting tired I can tell I’m not as focused as I would be in the morning. The bread is delicious. It is some of the best bread I’ve made yet. It is about time to cut the second loaf.
With a little more than an hour to go, it doesn’t seem like I’ll be getting very far in my little experiement, but I’ve learned a lot about Rails. That was kind of the point.
I found Rails Cookbook with exactly the kind of authentication required example for which I am looking. I’ll have to review it to see what kinds of implications it has for my current design.
The second loaf of bread is delicious. I was going for honey wheat, but it didn’t come out that sweet. It is some damn good bread though. I’ve had two pieces of each kind. That is a lot of bread.
No, I didn’t have a time set, I just found LoginGenerator and figured I could blog on that and call it a night. The time just happened to be midnight when I checked it.
4.5 hours later, I don’t have anything near an application. All I have are a bunch of screwed up Model and Controller files, and a whole lot more Rails knowledge. The Login Generator definitely looks cool. I’ll definitely be trying that out soon.
The Authors login example from the Rails cookbook works, but has an annoying bug that if you login incorrectly, it redirects indefinitely. I’m not sure why the authenticate action is being called on redirect_to action=>”index”, but it is. Hopefully this Login Generator will help.
Major Bummer. It seems Login_Generator is an optional addon to rails to be installed via Gem. Ubuntu doesn’t package gem nor Login_Generator. So my options are to build ruby from source, or figure a way to package it. I’m leaning toward the later for the benefit of all ubuntu folk, but it won’t be tonight.