Annoying Flash Issues

Posted by Sam

So I'm working on the Barkley Holiday site for 2007 and I ran into several frustrating things today. A little background on the site. The backend is written in Ruby on Rails and the frontend is flash based. I use LiteSpeed's excellent web server for the application and web server. The backend of the site is pretty simple. It's using the attachment_fu plugin to upload and resize photos and then simple XML to communicate with the Flash frontend.

The first problem I had today was that Flash couldn't get the XML when running inside IE6 on Windows. It works everywhere else. Grrr. The Flash developer found an article that was mostly wrong, but had just enough truth to help me find the real problem. When using rxml templates Rails will automatically return a content type of 'application/xml'. For whatever reason when you combine this with gzip compression, Flash and IE6 you can run into a situation where IE6 won't push the XML to Flash. If you turn off the compression it works fine. I turned off compression in LiteSpeed for dynamic content and everything worked. I really wanted the compression so I kept poking around to see if I could find another solution. Turns out if you leave compression enabled and change the content type to 'text/xml' then everything works fine. Stupid Internet Explorer! So if you are using Flash with RXML, IE6 and dynamic gzip compression you should set the content type like so. @headers['Content-Type'] = "text/xml"

The next problem I had with Flash was that images weren't being resized with attachment_fu when they were uploaded from the Flash frontend. If I loaded them with the backend HTML interface everything worked as expected. This turned out to be a relatively easy problem, but it still bugs me. Flash doesn't set the correct MIME type when it uploads files. Instead of uploading the files with a MIME type of 'image/jpeg', 'image/jpg' or something sane Flash pushes files up with a generic 'application/octet-stream' MIME type. Attachment_fu was seeing this MIME type and didn't think it was an image so it wouldn't resize it. Since we are only uploading images to this particular application I hacked the attachment_fu plugin to accept 'application/octet-stream' as a valid image MIME type. There might be a better way to do this but I needed it done yesterday so here is the original code found in attachment_fu > lib > technoweenie > attachment_fu.rb. #original code
@@content_types = ['image/jpeg', 'image/pjpeg', 'image/gif', 'image/png', 'image/x-png', 'image/jpg']
And here is the code with the MIME type needed to process Flash uploads. #hacked code
@@content_types = ['image/jpeg', 'image/pjpeg', 'image/gif', 'image/png', 'image/x-png', 'image/jpg', 'application/octet-stream']

I'm not sure if the first problem that I ran into is Flash's fault or IE6, but the second issue definitely seems like a problem with Flash. The browsers push up the MIME type so why can't/doesn't Flash?

Tags: rubyonrails litespeed

The little things

Posted by Sam

It's the little things in life that make a big difference. I recently ran into a problem where I thought ImageMagick was corrupting my images when it resized them. Turns out the problem was the database. In my migration I'd only specified :binary for the datatype. It looked like this. create_table :db_files do |t|
 t.column :data, :binary
end
Well in MySQL this means that it defaults to a Blob which only holds 64k. Originally the images were being scaled to 182x182 so this didn't present a problem as all the images seemed to come in under 64k. A couple days later I had to adjust this to 250x250 and then we started getting 'corrupt' images. Turns out some images just needed more space and some didn't. I looked through my Agile Web Development in Rails book and only saw a Binary datatype and didn't find an obvious way to make it bigger. Then I stumbled across a page that talked about setting the size to have a bigger limit and ActiveRecord will automatically give you a larger Blob datatype. In order to accommodate the bigger images I created the following migration. class ChangeMaxImageSize < ActiveRecord::Migration
 def self.up
  change_column :db_files, :data, :binary, :limit => 512.kilobytes
 end

 def self.down
  change_column :db_files, :data, :binary
 end
end
Woo Hoo! Thankfully that solved it.

Some frameworks look great on the surface and the more you use them the uglier they get. That was certainly my experience with Struts. It created as many problems as it solved. I've had a very different experience with Rails. It constantly surprises me with how well thought out and usable it is. I'm not a Rails fanboy I just like things that work and for most cases Rails just works.

Tags: rubyonrails

Ruby DTrace Probes in Leopard

Posted by Sam

There are a ton of new features in the upcoming release of Mac OS X code named Leopard, but there are a couple of features that I find pretty exciting and interesting but haven't seen mentioned elsewhere. The first is that Apple added DTrace probes to their version of Ruby. See the official page here. These probes were available on Solaris for a while thanks to Joyent, but I didn't realize Apple was including them in Leopard.

The second interesting feature (interesting to developers at least) is an app called Instruments. You can use DTrace probes to see exactly what is happening inside your Rails app while also seeing exactly what affect it's having on your system. It's got a great gui that I think will extremely useful for tracking down performance problems.

Mac OS X was already the platform of choice for Ruby on Rails developers but now it's even better. Apple is doing a great job of picking the best technology available and tying it into their OS. Now the only thing I'm waiting for is full ZFS support! For me it's Solaris on the servers and OS X on the clients. This combination will take over the world. Mark my words.

Tags: macosx dtrace rubyonrails

Easy Custom Environment in LiteSpeed for Rails

Posted by Sam

Update (8/12/2008)

Thanks to LiteSpeed adding a staging environment this work around is no longer necessary for me, but I'm leaving it here in case others need custom environments besides staging.

Ruby on Rails has three standard environments. Development, test and production. Test mode is also called staging by a lot of people, including myself. Unfortunately, my favorite web server and all around best Ruby on Rails application server, LiteSpeed, doesn't have a test mode. For whatever reason they implemented the development and production modes for Rails but didn't include a test mode. This is annoying because any real application development should be going through some formal or informal QA and this should be happening on a dedicated staging environment.

There are a couple of ways around LiteSpeed's lack of a test mode for Ruby on Rails. One of them is to simply set the RAILS_ENV variable in the environment.rb file like so. # Uncomment below to force Rails into production mode when
# you don't control web/app server and can't set it the proper way
ENV['RAILS_ENV'] = 'test'
I don't like this because if you push this exact same code to production it will override the default value, which should be production. That could cause all kinds of problems. Since I do all my pushes (both personal and professional) straight from subversion I would have to remember to make this change every time I pushed a site update to staging. It just feels wrong.

Another options is to forgo the easy Ruby on Rails setup in LiteSpeed and do a custom setup as described here. But then you will have the problem this guy had. Obviously it's doable but still seems dirty.

I prefer to stick with the standard and obvious way of doing things whenever possible. When you have to quickly migrate a server at 3 in the morning I have learned that keeping things straight forward is the best approach. Sometimes I will go to great lengths to keep something simple when a quick and dirty approach would have sufficed for a while. Keeping things standard and clean is the best approach. So, that being said, this is the approach that I think works best for setting up a test (or staging as we call it) environment in LiteSpeed. Change the environment.rb file in your Rails so that it reads: # Uncomment below to force Rails into production mode when
# you don't control web/app server and can't set it the proper way
ENV['RAILS_ENV'] = 'test' unless ENV['RAILS_ENV']
Basically you are saying if you don't know what your environment should be, set it to test. Now you need to make sure that the RAILS_ENV is not set by LiteSpeed so go to Configuration > Virtual Host Templates > EasyRailsWithSuEXEC > Context > Edit and select the blank option in the Rails Environment section. Restart LiteSpeed and your custom environment should be loaded.

Tags: rubyonrails litespeed

LiteSpeed Ruby on Rails Optimizations

Posted by Sam

LiteSpeed and Ruby on Rails are a dream come true. If you are deploying Rails apps on anything else in a production environment you are nuts. Not only is LiteSpeed/Rails one of the fastest (if not THE fastest) combinations for serving up Rails, it's also by far the simplest. LiteSpeed is also many times faster than Apache at serving regular files. Benchmark it for yourself and you'll see that it is indeed many times faster. So like I said, you are nuts if you are using anything else for your Rails applications.

One of the things that I do find annoying though is that by default LiteSpeed shuts down Rails applications after one minute of inactivity. Which means that if somebody hits your site every two minutes they have to wait for LiteSpeed to reload your application every time they hit a dynamic page. Which, even on a fast machine, might take a second or more. To change this in LiteSpeed 3.2.2 go to the Ruby Rails tab and change LSAPI_MAX_IDLE to the same value as "Max Idle Time". I set mine to 3600 seconds (one hour). LSAPI_MAX_IDLE=3600 After one hour if nobody hits your Rails site then it will unload and free up memory. Of course all of my sites are monitored with Nagios every five minutes so there is always at least one Rails instance running. Check out LiteSpeed's Ruby LSAPI page for more information on tuning Rails on LiteSpeed.

Tags: litespeed rubyonrails