Archive for the 'Web Development' Category

Facebox for Lowpro

Nov 09, 2008 in Javascript, Web Development

I really like both jQuery and Facebox but sometimes I do need to work with Prototype.

I found a couple of conversions of Facebox for Prototype. After finding these it didn’t take too much work to convert it to Lowpro.

The usage is simple:

Event.addBehavior({
  'a#fbox' : Facebox
});

The code can be found on GitHub.

Squish the slug the Rails way

Nov 06, 2008 in Ruby, Web Development

Recently Pat wrote about writing a quick method for making URL slugs. In the spirit of sharing I thought I’d mention a strategy I use in a number of the Rails apps I work on:

Take this code put it in a file named inflectors.rb in your config/initializers directory, and you’re good to go.

Tags: , , , ,

`is_blank` Function for PHP

Mar 24, 2008 in PHP, Web Development

One thing I love from Rails is the ability to do a .blank? method on any object. This is infinitely useful when you can’t be sure what type of value a variable is, or if it can potentially be different types. This is something that I always miss in PHP. Indeed since form data always comes back as strings and different ORM’s and database connectors (PDO, Propel, Doctrine, mysqli, PEAR DB, PEAR MDB2, etc) return different types, having a generic “is this value essentially blank, null, false, empty” is important.

A while back I set out to try and duplicate this functionality in a PHP function. Over the course of the past few months I feel it’s slowly matured and become something extremely valuable that I can’t live without.

It returns true when ever it is sure a value is blank, and false otherwise. It considers NULL, and false to be blank, and true to be not blank at the start. It then considers integers of 0 to be blank, and floats of 0.0 to be blank. It considers any string that is only composed of blank space characters, or “0″’s to be blank. I have considered adding a string of “false” or “null” but for now I considered this not to be generalizable enough. I feel that a string just of “0″’s almost always counts as a blank value when I’m processing data, but I could possibly see a string of “false” or “null” representing a non-blank value.

Then we get to the difficult part, arrays. The function of course regards an empty array as blank, but it will also recursively (this is performed by calling its self) go through all elements and if they are all blank declare the whole array blank.
There is also the special case of Objects that developers wish to be considered enumerable/iterator/array-like objects. These are created by implementing the SPL iterator interfaces. So the function checks to see if the necessary interfaces are implemented, and if they are treats the object, exactly like it would an array.

The last rule is it considers all other objects to be not blank.

This function can of course be expanded or refined to meet your particular needs. If, for instance, you have a self-defined Null object that you use you get set that to return true. Or if you don’t want strings with just “0″ in them to return true, you can change that. The function is very simple and it should be obvious where you change things to get the result you want.

Here’s the code:

function is_blank($value){
   $type = gettype($value);
   switch ($type) {
      case 'NULL':
      return true;
      break;
      case 'boolean':
      if ($value === false)
         return true;
      break;
      case 'integer':
      if ($value == 0)
         return true;
      break;
      case 'double':
      if ($value == 0.0)
         return true;
      break;
      case 'string':
      if (preg_match('/^\s*0*\s*$/', $value))
         return true;
      break;
      case 'array':
      if (count($value) == 0)
      {
         return true;
      }
      else {
         $all_blank = true;
         foreach ($value as $item) {
            if (!is_blank($item)){
               $all_blank = false;
            }
         }
         if ($all_blank){
            return true;
         } else {
            return false;
         }
      }
      break;
      case 'object':
      $implements = class_implements($value);
      if (
         in_array('ArrayAccess', $implements) && 
      (
         in_array('IteratorAggregate', $implements)  || 
         in_array('Iterator', $implements)           || 
         in_array('SeekableIterator', $implements)   || 
         in_array('RecursiveIterator', $implements)
         ) && 
         in_array('Countable', $implements)
         )
      {
         if (count($value) == 0)
         {
            return true;
         }
         else {
            $all_blank = true;

            foreach ($value as $item) {
               if (!is_blank($item)){
                  $all_blank = false;
               }
            }

            if ($all_blank){
               return true;
            } else {
               return false;
            }
         }
      }
      break;
      default:
      return false;
      break;
   }
   return false;
}

Pastie: http://pastie.textmate.org/169940
Pastie code download: http://pastie.textmate.org/pastes/169940/download

Tags: , , , ,

:include_blank => options

Mar 10, 2008 in Ruby, Web Development

So one minor thing I found annoying while working on Heelshousing was that, options_for_select, and options_from_collection_for_select didn’t accept an option or argument for :include_blank. So I created a little file called “include_blank_options.rb” that I threw in my “config/initializers” directory. Here’s the code:

module ActionView::Helpers::FormOptionsHelper
         
   def options_for_select_with_include_blank(container, selected = nil, include_blank = false)
      options = options_for_select_without_include_blank(container, selected)
      if include_blank
         options = "<option value=\"\">#{include_blank if include_blank.kind_of?(String)}</option>\n" + options
      end
      options
   end
   alias_method_chain :options_for_select, :include_blank
   
   def options_from_collection_for_select_with_include_blank(collection, value_method, text_method, selected = nil, include_blank = false)
      options = options_from_collection_for_select_without_include_blank(collection, value_method, text_method, selected)
      if include_blank
         options = "<option value=\"\">#{include_blank if include_blank.kind_of?(String)}</option>\n" + options
      end
      options
   end
   alias_method_chain :options_from_collection_for_select, :include_blank
   
end

Tags: , , ,

New Release of UJS Date-Picker Rails Plugin

Mar 08, 2008 in Ruby, Web Development

I’ve now updated my date-picker Rails plugin based on Brian McAllister’s Unobtrusive Date-Picker Widget. It now includes helper methods for making selects that wrap a ActiveRecord model object, or just a date/time value. It also includes many more options, mostly offering pragmatic ways of adding the options available to controlling the date-picker widget through html classes.

I’ve also created a large number of specs (with RSpec) for testing the plugin. Amazingly, testing plugins is actually really hard task, which I’ll probablly cover in a future post.

I’ve created a wiki page for Documentation and updated the RDoc’s.

If your using the plugin, and have any questions or concerns, or bug reports feel free to contact me.

Tags: , , , ,

Converting Video to Flash in Rails

Mar 07, 2008 in Ruby, Web Development

Video is fairly prevalent on the web these days with services like YouTube, and Joost. And indeed one the features that our client (the Daily Tar Heel) wanted for HeelsHousing was to have a video tour of properties.

I wanted to take the YouTube model and allow property owners to upload videos in any format they had them in and for us to show them in Flash video so that as many users as possible would be able to view it. So I set out constructing the process via which this would occur.
It would start out with a user uploading a video. The file would be moved to a temporary location (although a Tempfile object could not be used as these files get deleted automatically, i.e. before the background process would get to it). This path would have to be saved, and status value given. Then a background process would have to be passed this information to convert the movie, make a preview image, and upload both to Amazon S3, then saving the record as finished. Additionally, this background process would need to notify the property owner if either an error processing the video occurred or it had been successfully converted and uploaded.

The video model class I created is very similar in many ways to the functionality offered by the attachment fu plugin. It handles taking the uploaded file and moving it to a temporary location, it deletes the files when the record is deleted, it keeps track of the preview image and video file paths on S3. It also has a status attribute for the different statuses a video can have: queued, processing, ready, and failed.

The most complicated part of the whole process is how to handle the file once it’s been uploaded and temporarily stored. This needs to be handled by a background process, for Rails the obvious choice is the BackgrounDRb plugin. The background worker I created starts by grabbing the related video record, and sets it’s status to “processing”. It then uses the RVideo library, which in turn uses ffmpeg and flvtool2, to scale the movie and convert it to flash video. Finally, it uses RVideo to make a preview jpeg image, and uploads both to S3.
If anywhere along the way an error occurs the video record’s status is set to “failed” and a notification email is sent to both the property owner and the administrator using ActionMailer. On the other hand if the whole process succeeds the worker sends an email to the property owner only, and marks the video record as “ready”.

The last step was to display the video on a given page. To do this I used SWFObject and the JW FLV Media Player. I created a simple helper to create the SWFObject javascript for the video.

All of the external libraries I can say were very easy to work with, and made creating this functionality much easier. But the one I loved the most was RVideo. This library is a little gem for anyone wanting to script out ffmpeg or flvtool2 commands in Ruby. I highly recommend it.

Tags: , , , , , , , , ,

Customizing ActiveScaffold

Mar 04, 2008 in Ruby, Web Development

At first I was a little skeptical about the ability of ActiveScaffold to really do everything I needed to do, and not involve massive amounts of hacking apart the code. It actually turned out to be fairly easy and offered a great solution for some of the administrative side of HeelsHousing.

First off while not very well documented in my opinion is the ability of rails to have and understand sub controllers, such as the URI “/admin/users” which would be the controller in “app/controllers/admin/users_controller.rb”. To do this just requires some code like this:

app/controllers/admin_controller.rb

class AdminController < ApplicationControllerend

module Admin
end

app/controllers/admin/user_controller.rb

class Admin::UsersController < AdminController

   active_scaffold :user do |config|end

end

Of course the main thing we wanted to do was to style it to match other administrative interfaces we were using. In case you don’t know already the ActiveScaffold team really thought ahead on this one and allows customization at pretty much every level. For sweaping changes that effect style most likely you’re looking at Template Overrides. Since we were looking to have all administrative forms look the same we just had to provide new template in the “app/views/active_scaffold_overrides/” directory. The templates that I found were needed for really doing what I we needed to do to change the look of the forms were the “_form.rhtml”, “_form_association.rhtml”, “_form_association_record.rhtml”, and “_form_attribute.rhtml” templates.

Of course you also often want to change the specifics of how a specific form input is generated for a given column is generated. And for this there’s Form Overrides. These are just little helpers in the helper file for the given controller. So say you want to change the type of input used for your password column on the User form, just add a method called “password\_form \_column” in the “user.helper.rb” file.
But let’s say you want to change all columns that are strings to function in a specific way, like say setting the size and maxlength attributes, well here ya go:

Article.columns.each do |column|
   if column.type == :string
      size = (column.limit > 59) ? 60 : column.limit + 1
      src = <<-end_src
         def #{column.name}_form_column(record, input_name)
            text_field(:record, '#{column.name}', :size => #{size}, :maxlength => #{column.limit}, :name => input_name)
         end
      end_src
      class_eval src, __FILE__, __LINE__
   end
end

Well there’s really lots more I could cover about active scaffold but I’ll let you sophisticats check it out for yourself. The documentation is top notch. All in all a great addition to your Rails toolbox.

Tags: , , , ,

My Server, Your Server, We All Shouldn’t Share a Server

Mar 01, 2008 in Ruby, Web Development

When Heelshousing began, the company I work for had never deployed a Rails app before. We decided after much thought, that RailsMachine would be a good fit for us. Through out they way they’ve been a great service, especially for someone like me who didn’t have a lot of experience setting up and maintaining a server.

But of course like with anything else I decided the “basic” setup needed to be customized. I started by building and installing the nginx server with the Fair Proxy Balancer module, and set up appropriate logrotate and init.d scripts for it.
I then decided, based on numerous recommendations and benchmarks out there, to install the Swiftiply gem and use Evented Mongrel. The is done by installing the gem sudo gem install -y swiftiply and then using env EVENT=1 mongrel_rails instead of just mongrel_rails.

I then needed to pick an image processor for resizing uploaded images, rmagick is of course the obvious and almost “default” choice (particularly at RailsMachine). But I had heard reports about it eating memory and being a performance hog. So I decided to go with FreeImage and the ImageScience Gem instead.

Then of course there’s the almost ubiquitous memcached. How could I forget that! I installed that, the memcache-client gem, and the mem_cache_fragment_store gem. We use memcache for sessions, and fragment caching (partly via the Interlock plugin and partly via the built-in Rails fragment cache).

Lastly, since videos can be uploaded and I didn’t want to force property owners to upload a specific format, or have to support embedding different formats I installed ffmpeg, to convert them all to flash.

We also decided to go with Amazon S3’s service for hosting the image and video uploads, as well as serving as an asset host for our stylesheets, and images. And besides the monumental failure they had the other week it’s been a great success. In case you don’t know it’s really easy to map a sub-domain of your site to S3 by naming the bucket that domain name (in our case “assets.heelshousing.com“), and then setting a CNAMErecord with your DNS that points that sub-domain to the appropriate S3 domain name (in our case “assets.heelshousing.com.s3.amazonaws.com“).
It’s also a good idea when uploading images to S3 to set the EXPIRES and CACHE-CONTROL headers for them. Here’s a sample of the code I use to do that:

   AWS::S3::S3Object.store(
      key, File.open(path), BUCKET_NAME, 
      :content_type => content_type,
      :expires => Time.now.years_since(10).httpdate,
      :cache_control => "max-age=315360000",
      :access => :public_read 
   )

I think that should be self explanatory, but if not: I set the key variable to the name/path I want to use on S3, I set the path variable to the path of the file on the local machine, I set content_type to the appropriate MIME type, and of course I set the BUCKET_NAME constant to the name of the bucket I’m using.

Overall these choices were meant to hopefully increase speed of response for the user and performance on the server while also allowing everything to scale well as the sites user base grows.

Update:
The title refers to how Rails apps should not be hosted in shared environments.

Tags: , , , , , , , , ,

My First Rails site is Live

Feb 29, 2008 in Ruby, Web Development

So I finally finished it after months of laboring and coding away, HeelsHousing.com is live! The site is geared towards UNC - Chapel Hill students looking for housing opportunities close to campus. It does this by auto-calculating a properties distance from “The Pit” (think of this as the center of campus for those of you that don’t know UNC). The calculation is done “as the crow flies” and thus can be manually overridden by administrators if they wish to use a distance based on road directions. The reason for this is that obtaining driving directions distance via Google Maps server side is essentially impossible, but calculating the distance between two points on the planet is just a few calculations away (via the Rails Geokit plugin). It then allows you to sort search results by Distance from the Pit.

Search Results Map Another one of the sites great features is it’s overall integration with Google Maps. You’ll find on every property page a map of where the property is. Also a little javascript pop-up box (not window) with the map will be displayed if you click the “Map It!” link in the search results.
Bus routes overlaid on Google Map And just to put the proverbial whip-cream on the sundae, If a property owner or administrator specifies that a property is close to certain Chapel Hill bus routes, those routes are overlaid on top of the map.

The Daily Tarheel, who commissioned this site from us, run the day to day operations of it. This includes adding and updating current properties, but also selling property listings to local property owners. They can specify 2 levels of paid owner user accounts with different levels of permissions. The owners can then specify different types of units for each property, and upload unit floorplans as well as property pictures and a video.

In my next post I’ll go over some of the back-end features used to create and host the site.

Tags: , , , , ,

Rails 2.0 regex to convert old Migrations

Dec 07, 2007 in Ruby, Scripting, Web Development

Rails 2.0 is here! I’m going to try to move the app I’ve been working on (at DesignHammer) over to take advantage of it. Doesn’t seem like it should take that long? But we’ll see ;-)

While getting started on that I wanted to try the new method for Active Record DB migrations. So I decided to rewrite all my old migrations (or at least the ones adding tables). I ended up crafting this regex to allow for a quick find and replace of the old style to be like the new style:

Find:

   \.column\s+(("\w+")|(\:\w+))\s*,\s+(\:(\w+))

Replace:

   .$5 $1

Tags: , , , , ,