jQuery and Long-Running Web App Processes: A Case Study
I was recently approached by a client’s system administrator with a small but interesting training/development project. The sys-admin, named Rod, had built a simple intranet web application that used a few PHP pages, running on an Amazon EC2 instance, to accept some user input and kick off multiple long-running server side QA deployment processes. He wanted to use Ajax to start the process as well as incrementally display its output, line-by-line, on the same web page. However, waiting for the entire process to finish to display its output was a poor user experience, and he wasn’t able to get an Ajax call to return any output incrementally over the lifetime of the request.
Rod asked me to help him get his web app working and train him on what I did to get it working. He admitted that this project was a good excuse for him to learn a bit of jQuery (a good example of keeping your tools sharp) even if it wasn’t necessarily the best solution in this case. I have always enjoy training others, so we fired up Skype, got into an IRC channel, and dove right in.
First, I started with the javascript development basics:
-
Install the Firebug add-on for Firefox
-
Use Firebug’s Console tab to …
javascript jquery php sysadmin
A Ruby on Rails Tag Cloud Tutorial with Spree
A tag cloud from a recent End Point blog post.
Tag clouds have become a fairly popular way to present data on the web. One of our Spree clients recently asked End Point to develop a tag cloud reporting user-submitted search terms in his Spree application. The steps described in this article can be applied to a generic Rails application with a few adjustments.
Step 1: Determine Organization
If you are running this as an extension on Spree pre-Rails 3.0 versions, you’ll create an extension to house the custom code. If you are running this as part of a Rails 3.0 application or Spree Rails 3.0 versions, you’ll want to consider creating a custom gem to house the custom code. In my case, I’m writing a Spree extension for an application running on Spree 0.11, so I create an extension with the command script/generate extension SearchTag.
Step 2: Data Model & Migration
First, the desired data model for the tag cloud data should be defined. Here’s what mine will look like in this tutorial:
Next, a model and migration must be created to introduce the class, table and it’s fields. In Spree, I run script/generate extension_model SearchTag SearchRecord and update the migration file to …
ecommerce rails spree
Ecommerce on Sinatra: A Shopping Cart Story
In a couple recent articles, I wrote about the first steps for developing an ecommerce site in Ruby on Sinatra. Or, here’s a visual summary of the articles:
|
|
| In the first article, a single table data model existed with a couple of Sinatra methods defined. | In the second article, users and products were introduced to the data model. The Sinatra app still has minimal customer-facing routes (get "/", post "/") defined, but also introduces backend admin management to view orders and manage products. |
|
|
In this article, I introduce a shopping cart. With this change, I modify the data model to tie in orderlines, where orderlines has a belongs_to relationship with orders and products. I’ll make the assumption that for now, a cart is a set of items and their corresponding quantities.
The new data model with tables orderlines, products, orders, and users.
An Important Tangent
First, let’s discuss cart storage options, which is an important topic for an ecommerce system. Several cart storage methods are described below:
-
Conventional SQL database models: Conventional SQL (MySQL, PostgreSQL, etc.) tables can be set up to store shopping cart items, …
ecommerce ruby sinatra
API gaps: an Android MediaPlayer example
Many programming library APIs come with several levels of functionality, including the low-level but flexible way, and the high-level and simpler but limited way. I recently came across a textbook case of this in Android’s Java audio API, in the MediaPlayer class.
We needed to play one of several custom Ogg Vorbis audio files in the Locate Express Android app to alert the user to various situations.
Getting this going initially was fairly straightforward:
In this simplified version of our PlaySound class we pass in the app resource ID of the sound file, and using the MediaPlayer.create() method is about as simple as can be.
We keep a map of playing sound files so that external events can stop all playing sounds at once in a single call.
We set an OnCompletionListener to clean up after ourselves if the sound plays to its end without interruption.
Everything worked fine. Except for a pesky volume problem in real-world use. MediaPlayer uses Android’s default audio stream, which seemed to be STREAM_MUSIC. That plays the audio files fine, but has an interesting consequence during the actual playing: You can’t turn the volume down or up because the volume control outside of any specific …
android java mobile api audio
SSH: piping data in reverse
I found myself ssh’d several hops away and needing to copy output from a script back to localhost. Essentially what I wanted was a way to get the data in question piped backwards from my SSH connection so I could capture it locally. Since I utilize .ssh/config extensively, I could connect to the server in question from localhost with a single ssh command, however bringing the data back the other way would make it a multi-step process of saving a temporary file, copying it to a commonly accessible location which had the permissions/authentication setup or intermediately sshing to each node along the path—in short it exceeded my laziness threshold. So instead, I did the following:
[me@localhost]$ ssh user@remote nc -l 11235 > output.file # long, complicated connection hidden behind .ssh/config + ProxyCommand
[me@remotehost]$ perl -ne 'print if /startpat/ .. /endpat/' file/to/be/extracted | nc localhost 11235I ended up choosing an arbitrary port and ran a remote listen process via ssh to pass on any output directed to the specific remote port and capturing as STDOUT on my local machine. There are a couple reasons I think this setup is nicer when compared to just …
sysadmin tips
Ecommerce Solutions: What are the Options?
Lately, I’ve been evaluating ecommerce options for use on a side hobby/business. I’m obviously a developer, so in theory I could use one of End Point’s supported ecommerce frameworks or just write my own framework. But, my bottom line is that I don’t need the feature set offered by some of the ecommerce options out there and I don’t necessarily have the resources to develop a custom solution.
In addition to personal interest, End Pointers constantly encounter potential clients who aim to get a better understanding of the cost of using open source, our preferred ecommerce solution. I put together two infographics on ecommerce options, ongoing cost, feature sets, and the ability to customize. Before anyone flips out about the infographics, note that they represent my broad generalizations regarding the ongoing cost, feature sets and ability to customize. I’m intimately familiar with some of these options and less familiar with a couple of them.
Feature Set versus Ongoing Cost of Ecommerce Solutions
Ability to Customize versus Ongoing Cost of Ecommerce Solutions
Some notes on on the ecommerce solutions shown in the infographics:
- Online payment service (Paypal): An online payment …
ecommerce interchange open-source spree cms magento
What’s the difference?
Not long ago a software vendor we work with delivered a patch for a bug we’d been having. I was curious to know the difference between the patch, a .tgz file, and the files it was replacing. I came up with this:
( \
for i in `( \
find new -type f | sed "s/new\///" ; \
find old -type f | sed "s/old\///" ) | \
sort | uniq`; do \
md5sum old/$i new/$i 2>&1; \
done \
) | uniq -u -c -w 32Assuming the original .tgz file was unpacked into a directory called “old”, and the new one into “new”, this tells me which files exist in one directory and not other, and which files exist in both in different forms. Here’s an example using a few random files in two directories:
josh@eddie:~/tmp/transient$ ls -l old new
new:
total 16
-rw-r--r-- 1 josh josh 15 2011-03-01 10:15 1
-rw-r--r-- 1 josh josh 12 2011-03-01 10:14 2
-rw-r--r-- 1 josh josh 13 2011-03-01 10:15 3
-rw-r--r-- 1 josh josh 12 2011-03-01 10:16 4
old:
total 16
-rw-r--r-- 1 josh josh 15 2011-03-01 10:15 1
-rw-r--r-- 1 josh josh 5 2011-03-01 10:06 2
-rw-r--r-- 1 josh josh 13 2011-03-01 10:15 3
-rw-r--r-- 1 josh josh 20 2011-03-01 10:18 5
josh@eddie:~/tmp/transient$ ( \
> for i in `( …tips
YUI Extensions and Post Initialization
When using YUI3’s provided extension mechanism to enhance (composite, mix in, role, whatever you like to call it) a Y.Base inherited base class, it is often helpful to have “post initialization” code run after the attributes’ values have been set. The following code provides an easy way to hook onto a Y.Base provided attribute change event to run any post initialization code easily.
javascript







