Monday, July 6, 2009

Phase II -- new plugin to evaluate

I'd like to evaluate this plugin for the equipment hierarchy, it's called "acts-as-dag" by Matthew Leventi.

/mieventi/acts-as-dag on github

It looks promising because it contains nice named scopes and allows multiple parents as well as multiple children. The searches are well thought out and it looks to be a fast interface (most calls are performed with one SQL call).

I'd hate to rip up the equipment tree at this point but now is the last time this could happen without it being a BIG deal. It might only disrupt the code a little. Still, the gain needs to be large enough to justify the disturbance.

The biggest problem I see with it is that it's not well maintained. It looks like Matthew created a year ago and then left it. One other person forked it and added to the code. So it looks like it might be immature but still, it looks attractive because of its capability for children to have multiple parents.

Tuesday, June 16, 2009

Tickling the blog

Nothing new to blog about except that I'm anxious to finish the documentary and get back to the app. This is the final edit, schedule to wrap on June 30, 2009. Then there's sound mix and color correction, which should take the rest of July to complete. But starting in July, I'll be getting back into the code and coming up to speed with what Lee has done.

Why isn't the documentary finished yet? It was ready to premiere at SXSW but a technical problem with the projector caused the screening to be canceled. (I turned down an alternate screening because I felt that the film wasn't really ready yet and the alternate screening would have been after all the out of towners had gone back home). So I've taken this opportunity to test screen it, get feedback, and then re-edit it one more time. It's much more solid but dang, I'm getting tired of editing it and I'm looking forward to it being finished! Two more weeks!

Wednesday, April 1, 2009

Starting to get itchy fingers

I still have a few more edits to do on the Blaze Foley documentary film but I'm starting to get excited about working on the reservation system again. In particular, I'm looking forward to seeing Lee's changes to the code (the nested models especially) and how the public-facing interface will look.

A friend of mine showed me a website he's been working on for the past few months and maybe that's what's gotten me into the groove of working on the reservation system. Looking at it, I realize that I really need a designer to create a new look for the website.

Since I can't dive into the code at this point, here are some more thoughts about Phase II of the project.

Checking for availability may be the most difficult aspect but I hope not. Getting the pickup date and time from the user plus the return date and time should be all it takes. And hopefully a named scope can be defined that takes the two datetime values and returns the set of all available contractables. The part that will make this easier will be the reservations table, where the physical, individual equipment items (as opposed to the nested packages of equipment items) are stored with the dates for which they are reserved. Keeping that table consistent and accurate will be the key to making it all work.

I don't know if this reservations table should be rebuilt periodically or just checked for accuracy on a periodic basis. But the table should be capable of being re-built on-demand from the other tables in the database.

Oh -- and I decided today that instead of running everything on Ruby on Rails, it'll run on .NET using VB on triple redundant Windows Server 2003 servers. Looking forward to joining the happy few who use this thing called Microsoft. (BTW, this was posted on April 1, so don't get fooled!)

Wednesday, March 25, 2009

Back after finishing the film

Now that BLAZE FOLEY INSIDE, my documentary about songwriter Blaze Foley is finished, I can turn my attention back to our application. Lee has done a terrific job of completing Phase I, getting a virtual server configured and upgrading the application to Rails 2.3.

The nice thing is that Lee has ripped out the attribute_fu plugin, switching in the nested_model feature of Rails 2.3. So now we're running with official Rails implemented nested models for contractables and users, which is nice.

Phase II will likely kick off at the end of April when I've submitted the film to the Toronto Film Festival. There are still a few minor edits I want to complete before submitting it. Currently, the runtime is 69 minutes and I want to get it up to around 74 minutes, which is more palatable for a film festival to program as a feature-length movie.

When I get back to the project full time, I want to attack the user interface and get it up to speed, more like an application. I also want to get familiar with the new code and see where the Phase II objectives will fit into and modify that code. I'm really looking forward to getting back to the app!

Tuesday, January 20, 2009

Phase II objectives

This is just a starting point for our next set of objectives -- this post will be edited as we refine them. (In the following, users are users who are employees and clients are users who are customers.)

- Deployment: Setup a production server to host the site so we can practice deploying and allow others to try out the UI and give us feedback. The new server will do double duty as I decommission my current AMP server, migrating existing websites to the new server.

- Availability: Checking the availability of contractables (equipment) is essential to the reservation application. Using the contract form, the user specifies the pickup date and time and the return date and time. A search of contractables should only return those contractables that are available (not already reserved) for that period. The application should resolve a race condition in which two people try to reserve the same contractable at the same time for overlapping periods. For quotes, the user might not specify dates, only a duration, in which case all contractables will be available it's just a quote and the dates for the equipment might be flexible). The user might also change the pickup and return dates and times and if they do, any contract_line_items which are not available for that new period should be flagged as unavailable but not removed -- in which case, the user must either 1) manually remove them or 2) change the period or 3) accept the consequences.

- Emails: Send emails to:

  • newly registered clients welcoming them and inviting them to activate their account,

  • clients who created new reservations asking them to confirm,

  • reminders to clients that a reservation is coming up soon and asking them to confirm,

  • notices to admins that a confirmation has not been received or that a cancellation has been received,

  • notices to third-party owners that their equipment has been reserved and asking them if it's available for that period,

  • notices to admins that a third-party confirmation has not been received,

  • notices to third-party owners of cancellations by clients,

  • notices to third-party owners reminding them of an upcoming reservation if they have not already dropped off their equipment.

  • Whew. There's probably more, this needs to become a list of email conditions. Although very useful to keep a tight running operation, email triggers will eventually need to be configurable so that their frequency don't become a nuisance.


- Public UI: Create the public facing pages to display contractables. Possibly create a side navigation feature that makes it easy to drill down into categories. Will need to try different UI ideas to find the right mix of familiar, simple and easy to use. Lots of AJAXy goodness here, real 2.0 shwiz. We'll need a graphics whiz to help with the layout.

- Auditing: Using Brandon Keeper's acts_as_audited plugin, we should be able to record changes to contracts and user records and see what those changes were and rollback those changes if needed. May open up the auditing to contractables as well.

- Authentication: Using Ben Johnson's authlogic plugin that moves the authentication domain into the model so it's transparent and yet has plenty of hooks for customizing. It is also encryption method agnostic, letting us choose or change the algorithm. It has plenty of nice features that we won't need but hopefully that's not a sign that the code is large and buggy. At least it's been around awhile, actively updated, tested and running on other people's apps.

- Navigation: Make the top-level site navigation prettier, not just an ordered list of links.

- Look into Matthew Leventi's plugin acts-as-dag as a way to organize the equipment hierarchy. Currently, we use a roll-your-own self-referential DAG. This could also replace the nested set table, which might be nice. It cuts down on the amount of repetition and maintenance.

Phase I nearing completion

After a burst of work, I've added unobtrusive JavaScript to the app to do a few AJAXy things -- the most important being easy adding/removing of items from nested contractables and adding/removing line_items (contractables) from contracts. Other niceties are AJAXy searches, AJAXy form submission, field focus, tabbed panes and client-side form validation.

The final step in Phase I will be to add nested contractables to contracts. Currently, only the top parent of a nested contractable is added to the contract. There are two ways to add the children: add them as separate contract_line_items or show them as children of the parent. I would like to show them as children of the parent so that if the parent is deleted, the children are deleted as well.

The reason for this choice is, the children may be discounted when rented as part of the nest (and the children can always be manually added and a future feature can be implemented that converts the nest into separate line items).

To just show the children, the contract_line_item would reference only the parent but the reservations table (that tracks what items are reserved for what periods) would contain a separate record for each child contractable that references an actual, physical item. (The reason being that the reservations table tracks physical item reservations, not nests or abtract groupings.)

After adding this logic and testing the app, we can call Phase I done.

Tuesday, December 30, 2008

Pretty views

Now that Phase I is almost complete, I can't resist making the views prettier. For instance, the user administration form is hellalong and the contract is pretty dang ugly, with all the capabilities on the same page.

For both of these forms, we can use tabs to hide panes of information that aren't of interest and show panes that are of interest. Since this capability requires JavaScript, we'll make it so that all the panes are visible when the browser does not have JavaScript enabled. So it will still be ugly and ungainly but the JavaScript-enabled version will be nice and compact.

I'm going to try Ajax Tabs developed by Flinn Mueller, not that any of our panels will necessarily be loading from Ajax but because they look nice (I like Flinn's simple CSS) and because the code looks clean. Of course, I'll be modifying his code to suit our purposes but it's a good start.

For the contract form, there's an interesting challenge in that there will be two sets of tabbed panes. I don't think that will be a problem for the JavaScript to handle but we'll see. I'll document the final design.

UPDATE: I decided to go with the .tabs feature that is built-in to the jQuery UI library, which made the JS code nice and simple, inserted in the _tabs.html.haml partial (serializing the tab_container_id allows multiple tabbed panes on one page):

- id ||= "ui-tab-container#{i}"
= javascript_tag "jQuery(document).ready(function($) { $('##{id}').tabs() });"

I created a Rails helper function to create each pane and store it in an instance variable and then concat it into the view. It's working very nicely:

#---
# create a section for tabbing
# options:
# css_class = section div class (defaults to 'right')
#---
def create_tab(title, opts={}, &block)
raise ArgumentError, "Missing block" unless block_given?
@tabs ||= []
@tab_count ||= 1 # allow for multiple tab containers
# remove whitespace and create the CSS ID from the title (#title-pane)
id = "#{ActiveSupport::Inflector.underscore(title).gsub(/\W+/,'_')}-pane"
# capture into a string, the pane that the block creates
content = capture(&block)
# if client is not running javascript, create a fieldset as an alternate way of grouping it
# TODO: come up with a better CSS method to handle none-form panes
unless @js
content = capture { render :partial => 'shared/fieldset', :locals => {:legend => title, :content => content} }
end
# save off this pane for later output
@tabs << { :id => id, :title => title, :css_class => (opts[:css_class] || 'right'), :content => content }
end

def output_tabs(id=nil)
concat(capture { render :partial => "shared/tabs", :object => @tabs, :locals => {:id => id, :i => @tab_count} })
@tabs = []
@tab_count += 1
end

Oh, and although I built the ability to have multiple tabbed panes, I decided that the contract form really only needed one.