IE7 header issues
July 20th, 2008
I got to deploy a new build to TheWineSpies.com this weekend, which among many other things, upgraded the app to rails 2.1. This process had me refactoring the admin to be RESTfull-er, and incorporating the latest version of Fleximage. I thought everything was dandy.
The Problem
My client was doing some testing on this code with IE7, their browser of choice. But something odd was happening. They would click a link triggering a resources show action, and instead of a html page about that resource, they would just get the image. At first I was stumped. I never thought cross browser issues could change server behavior. Firefox got a page of HTML and IE7 got an image. And I confirmed that the server was actually sending different content to the different browsers. The truly bizarre part, was that after clicking a link to this page, you could refresh and get the content you were expecting.
What the hell?
The Code
The Wine Spies uses Fleximage enahnced models across a few different resources, but here is a simple action that was causing me grief.
1 2 3 4 5 6 7 8 9 10 |
def show @product = Product.find(params[:id]) respond_to do |format| format.html format.jpg { render :template => '/some/path/small.flexi' } format.xml { render :xml => @product.to_xml } end end |
This is pretty straightforward.
- If
htmlis requested, render the default template - If
jpgis requested, render some.flexitemplate - If
xmlis requested, dump the object to xml and send it out
But still, IE7 on a url of /products/123 would trigger the jpg format renderer. Somehow rails was thinking that IE7 wanted a jpeg image instead of HTML. Where other browser were making rails think they want HTML unless overridden by a format extension on the url.
Tracking down the cause
I began to think back to the DHH keynote “World of Resources” and some of the early stuff that was forming around rails, and luckily, I remembered something important. I tend to use this format pattern a lot, and I usually trigger it by url extensions like /products/123.jpg or /products/123.xml. But rails looks at something else too.
Your browser, or any HTTP client, sends along a header named HTTP_ACCEPT with any request. I decided to add some debug code to my action to see what was in this header:
raise request.headers['HTTP_ACCEPT'] |
In Firefox 3, the result was (minor edit for simplicity):
text/html,application/xhtml+xml,application/xml,*/* |
This is a comma separated list of MIME types. The purpose of this header is to let to receiver know what kind of data the client wants, or what it will “accept”. It’s a prioritized list where the first items are wanted more then the items at the end of the list. Firefox is saying “Please give me html. If you don’t have that give me xhtml. But I guess xml would be ok too if that’s all you got. You got none of those? Well give me whatever you got then, I don’t care.”
Ok what does IE7 send?
image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/ag-plugin, */* |
Until I refreshed the page, instead of clicking a link to this page, and got:
*/* |
What the hell?
IE7 doesn’t say it wants HTML at all! It says it would rather have a gif, bitmap, jpg, flash, or even a plugin, rather than any other MIME type, including html. Rails gets this header, and sees that is no explicit format on the URL, so it goes down the list:
- Does this action respond to the
image/gifformat? nope. - How about the
image/x-bitmapformat? no. - Maybe the
image/jpegformat? Oh look at that yes it does!
The item that would have matched the html renderer */* is too far down the list, and we don’t get to it before a suitable responder is found.
Since IE7 sends a different HTTP_ACCEPT of */* on a refresh, it is declaring it has no preferred format at all. Rails then renders the default: html.
The Solution
After trying many ways to capture the damn header, override it somehow, shoving some Mime::Type object into request.format, and other failed solutions, here is what I finally ended up with:
1 2 3 4 5 6 7 |
#application.rb before_filter :set_default_format def set_default_format params[:format] ||= 'html' end |
This basically tells rails to ignore the HTTP_ACCEPT header. If a format is not explicitly declared on the URL, then force it to be HTML. It’s as if every html page on the site has a .html appended to the URL.
And finally salvation from that circle of hell.
Conclusions
What makes a good HTTP_ACCEPT header? I think Firefox has it right. Being a web browser, its main job is to display HTML, with embedded media. So it should want HTML more than anything since the images are just there in support of the html (mostly anyway).
IE7 makes 2 mistakes:
- It sends different headers depending on how the page was loaded
- It states that is prefers images over HTML
HTTP headers are a powerful tool. They can make interfacing with web applications and API’s much cleaner. But as we depend on them increasingly, we need have a level of trust with the clients that people use to connect. IE7 said it wanted one thing, and I forced to create a hack in order to tell IE7 “No, you don’t really want that. You really want something else.” And that makes me sad.
I thought clients who don’t know what they want are pain, but now browsers have the same problem. IE7 is a huge improvement over IE6, however it obviously still has its issues for web developers. The simple fact is that both versions of this browser have cost me way too much time, and that means it cost me money. The number of hours I have spent troubleshooting issues like this, as well as CSS and javascript issues, is way more than I want to admit to.
And that makes cranky. So tell your parents, “Save a web developer. Switch to Firefox.” Then maybe the world will be a better place.
Rails Documentation Patches
May 21st, 2008
I have just commited a documentation patch to Rails which adds instructions on how to use ActiveResource::HttpMock to test your ActiveResource models. But the really cool thing is how easy it was to do.
If you ever have been frustrated because something wasnt documented clearly, or documented at all in the case of ActiveResource::HttpMock, I really encourage you to fix up that part of the rails documentation and commit a patch. The steps are simple:
- Read the docrails conventions wiki page
- Send lifo:”http://github.com/lifo” a message asking for commit access to the docrails project on GitHub. You may want to include a brief description of what you intend to fix, just so he knows your cool.
git clonethe docrails project, and write some documentation.rake rdocand review that the new documentation looks great when converted to HTML.git commitandgit push, and you are now a rails contributor!
A useful tool in this endeavor was rstakeout. It’s a script by Geoffrey Grossenbach that allows to run a command everytime a set of watched files changed. You can use it to run tests, compile HAML or SASS outside of rails, or generate the documentation when you save.
Copy this script to somewhere in your PATH and make sure its executable. Remove the .rb extension so it can be called like any other command line program. Now when working on the documentation:
cdinto the rails component you are writing documentation for.rstakeout "rake rdoc" lib/**/*This will watch all files in all directories directly underlibfor changes. This is a typical glob format and you can use as many globs as you like if you want it to watch lots of files.
Now everytime you switch over the your browser, the newly generated docs will be up to date and waiting for you to preview them after a simple refresh. Sure does save you some time.
Fleximage now form redisplay safe
April 15th, 2008
There was a minor annoyance with all version of Fleximage up to this point. If you upload an image to a model, and validation fails for whatever reason, then you would have to find the image on your disk again, re-upload the image again, before you resubmit the form. Wouldn’t it be nice of the file stayed uploaded, even if the record isnt ready to be saved yet? How about getting a preview of the uploaded image too?
It’s all possible with the latest version of Fleximage up on GitHub. Checkout this GitHub wiki page for details.
Settings Plugin update
April 12th, 2008
Since GitHub makes open source so easy I opened up my old Settings plugin after almost a year and put it up with a few improvements.
Most importantly, I got the tests working. I also created a less ugly way of defining defaults:
1 2 3 4 5 6 |
Settings.defaults[:foo] = 'bar' # or Settings.defaults = { :foo => 'bar', :baz => 'faz', }.with_indifferent_access |
Ruby Experts
April 6th, 2008
Hey look, I’m a Ruby expert
Not sure how I stack up with people that wrote Ruby books… Had I realized that I was going to be quoted in such a manner, perhaps I would have answered with slightly more verbosity. Live and learn.
Heroku and the Hillcrest Development Watch
March 29th, 2008
A friend asked me to donate a tiny google maps application to a non-profit cause. The Hillcrest Development Watch monitor housing and construction in their area and they wanted an easier way to do it than emailing a spreadsheet around. Now, being a Rails programmer, of course I wanted to deal with this in Rails. Sadly Rails is a pain to host right?
Wrong. Enter Heroku. Their fantastic setup is free (for now). They create a git repository for your app when you create your app. Then you simply suck down that git, commit to it and push it back. Their server software automatically updates your working code and reboots your app to the latest code, simply by pushing your commits to the server. It is the least painful rails deployment process I have ever used. In fact, I would go so far as to call it pleasurable, which is a big deal to say about rails deployment.
Check out Hillcrest Development Watch
The site itself is a simple single resource web app. It tracks properties, their addresses and development states. For a supre small app like this, Heroku even provides access to its user login system. It lets you use the user logged into heroku.com as a user in your app. So if your needs are simple, you can have a user authentication system, and have your app not care about registration, authentication, or user management. This app simply show some admin function if the user is authorized to edit this heroku app. This wouldn’t stand up to the needs of anything more complex, but it saved a huge bundle of time for this project.
In case this lengthy prose didn’t convey my point:
Heroku is Aweome!
FleursFrance.com
February 21st, 2008
I have been developing a little site for the florist of my recent wedding. It’s a simple custom designed Rails CMS. Its got some page content management, a cool gallery manager, and of course, FlexImage is used to resize images and stamp them with a custom copyright.
The main problem with the images is that some were taken by the florist herself, but other are taken by professional photographers, and proper credit needed to be given. So I provided a simple text field that will write anything to the bottom left of an image allowing custom copyright on a per photo basis. And permanently stamping it on the image meaning it can’t be stolen, at least without a nasty cropping, but there is only so much you can do against that.
It’s been a fun little project.
Invisbly remember state with Ajax
July 22nd, 2007
A few times now I have used a useful pattern. The problem is that I want to remember the state of a javascript driven effect across multiple pages. For instance, one of my projects has a context sensitive administration pane that can be shown or hidden on any page. I want someone to be able to show this admin pane, go to another, and have the admin pane for that page already opened. Then I want them to be able to close the pane, and have it stay closed on all pages until it’s manually opened again.
How do manage this, when the opening and closing of the pane is entirely client side driven javascript? With Ajax, of course!
Read the rest of this entryHaml and Sass
June 23rd, 2007
I have now begun a project that I plan to do entirely and Haml and Sass. In case that’s Greek to you, checkout this page out.
So far, I like then both. Although I like Sass much more than Haml. Maybe it’s because CSS is more broken than XHTML as far as ease of authoring. And Sass greatly improves the ease CSS authoring. The constants, the nesting, the math. It’s all just brilliant. Sass improves CSS creation in virtually every way.
For example, here’s some Sass:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
body.home-index
img.photo
:float right
:margin-left 5px
h1
:text-align center
:line-height 0.9em
span
:font-size 26px
:color #5DB63C |
And the corresponding CSS:
1 2 3 4 5 6 7 8 9 10 11 |
body.home-index img.photo {
float: right;
margin-left: 5px; }
body.home-index h1 {
text-align: center;
line-height: 0.9em; }
body.home-index h1 span {
font-size: 26px;
color: #5DB63C; } |
Haml, on the other hand, does improve standard XHTML authoring quite a bit, but it comes with some drawbacks. I think this is mainly due to the whitespace restrictions. For instance, if I want this HTML.
1 2 3 4 5 6 7 8 |
<h1> Ruby<br /> <span>on</span><br /> Rails </h1> <p> Rails is <strong>Awesome!</strong> </p> |
I have to use this haml
1 2 3 4 5 6 7 8 9 |
%h1 Ruby %br/ %span on %br/ Rails %p Rails is %strong Awesome! |
I guess Haml handles the block level stuff well, but the inline markup can make your template messier and harder to understand than it’s XHTML equivalent.
The other thing that bothers me about Haml is the lack of closing tags. I know, this is by design of the language. But what I am used to is to create a closing tags along side every opening tags. The bodies of those tags get flushed out, and I know exactly where the next element goes based on the closing tag. With only indents to guide your nesting, I have had to scroll up and down in a big page and try to discern just where a particular element stops. Or what indent level to stick a new element.
Perhaps, I’m just set in my ways. I think I’ll get used to it, but it still bothers me a bit. And, to be clear, I still think this is an improvement on RHTML and plan to use it in more projects.
Short Version
- Haml: Cooler than Rhtml, most of the time.
- Sass: Utterly and Completely fantastic
New FlexImage website and repository
June 20th, 2007
This information is now old. A new version of the plugin can be found here with lots of instructions and examples.
FlexImage has officially been moved to RubyForge. Find all the new Goodies here:
fleximage.rubyforge.org
New SVN: svn://rubyforge.org/var/svn/fleximage
It’s got a new getting started guide, as well as an extensive examples section.
The README is still a bit out of date and I will hopefully be updating that soon. But this new site should make it far easier to get people up and running with FLexImage the right way, and get them doing it properly, with .flexi templates and all that jazz.
Just in time for me to show this off tomorrow night at the North Bay Ruby Users Group. All you Sonoma County Rubyists may as well stop on by!
super is awesome
June 7th, 2007
First of all, sorry for the lack of posting lately. I do have lots of goodies, it’s just been a bit crazy lately. I have transitioned from 9-5 desk job, to a chaotic and uncertain freelance-ish position. And yeah, it’s been a little nuts.
Anyways, on to some ruby goodness.
I am going to give a small example of how awesome the super method is. In case you don’t know super is a special method that executes the parent method of the same name. Confused? Try this simple example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Foo def bar 'Bar!' end end foo = Foo.new foo.bar # => 'Bar!' class Foo2 < Foo def bar "This method says: " + super end end foo2 = Foo2.new foo2.bar # => 'This method says: Bar!' |
When foo2 calls bar it calls super witch executes the method in the parent class with the same name. This lets us append something to the returned value without have any idea what it is.
Now for a cool example with a modified Builder::XmlMarkup class.
Read the rest of this entry
"returning" method and prettier code
April 26th, 2007
I have used a little method called returning more and more lately. The implementation of it is built into rails, but the code is incredibly simple:
1 2 3 4 5 6 |
class Object # all classes inherit from object so this available anywhere. def returning(value) yield(value) value end end |
Doesn’t look very exciting, does it? Well first lets look at some code that doesn’t use form the latest app I am working on:
1 2 3 4 5 6 7 8 |
def self.shipping_rates(zip, weight) rates = UPS::Rates.call(zip, weight) rates.each do |rate| rate.price += Settings.handling_base_price rate.price += Settings.handling_bottle_price * qty end rates end |
So here we get the result of an API call, and we store it in a local variable. The we process it by inflating the prices a bit. Lastly we have to return the rates object since, in this case, the each method returns an array, not my my enumerable object.
I seem to see this pattern a lot. Create an object, iterate through/modify it, return the original object with modifications. The problem is that your modification methods do not return the value you want the whole method to return so you have to manually give it a value to return as the last line. It works but it just feels ugly to me. Adding that last line that does not do anything but only serves to return the proper value just feels messy.
What if we could make this clearer and prettier:
1 2 3 4 5 6 7 8 |
def self.shipping_rates(zip, weight) returning UPS::Rates.call(zip, weight) do |rates| rates.each do |rate| rate.price += Settings.handling_base_price rate.price += Settings.handling_bottle_price * qty end end end |
The method is still 6 lines, but it’s far cleaner. The returning method does two things:
- It returns that object you pass to it as an argument.
- It yields the object you pass to it in the attached block.
That’s it. So you can encapsulate this pattern in a simple way. It allows you to modify an object however you want in a block without having to worry about the return value. How many bugs have been tracked down to a model method that does the right thing, but returns the wrong thing. This makes it easier. And, at least in my opinion, much clearer and readable as well.
The wonderful magic of the association proxy
April 16th, 2007
UPDATE: This post here does a much better job at explaining how cool the association proxy is. Check it out.
I stumbled onto a feature I didn’t even know Rails had today, simply because it felt like that’s the way it should work. I didn’t even realize the leap of faith until after the test passed and I realized what was going on.
Let’s say you have a model Foo with a class method called get_snazziest. Now let’s say that Bar has_many :foos@
Here is the cool part:
Read the rest of this entryFlexImage update: now multi-class safe
April 12th, 2007
This information is now old. A new version of the plugin can be found here with lots of instructions and examples.
NOTE: Before you update your plugin, install the dsl_accessor gem.
gem install dsl_accessor
Sorry it took so long guys, but FlexImage now has full support for multiple classes with different settings. The problem with class variables (the @@foo variety) is that if they point to the exact same object in all classes that inherit from the class it was defined in. For example:
class A
@@foo = 'A'
def self.foo
@@foo
end
end
A.foo #=> "A"
class B < A
@@foo = 'B'
end
A.foo #=> "B"
B.foo #=> "B"
So changing @@foo in the class B, changes it in class A, as well as it’s siblings.
The solution
There is a great gem out there class dsl_accessor. It provides a way to declare inheritance safe class level variables through an elegant API. I have transitioned all class level variables in FlexImage from the old @@foo style to the new and sexy accessors.
This also means some syntactic sugar (although, still backwards compatible). Where before you had to declare these values like this:
self.file_store = 'path/to/master_images'
Now you can do any of the following:
file_store 'path/to/master_images'
self.file_store 'path/to/master_images'
self.file_store = 'path/to/master_images'
And rest assured that all attributes are safe from their parent and siblings.
Found a bug?
As always, simply post here with any problems you may have and I will assist as best I can.
Happy Flexing!
Helpers and Blocks
February 22nd, 2007
In rails 1.2 a new kind of helper was introduced with form_tag. This helper method not only takes a block, but wraps content around that block, even though it’s called with <% %> rather than <%= %>. Odd, but ever so useful.
Here’s how to write your own helper that can take a block of ERb.
Say you want to wrap a bunch of random content in a div that hides itself when clicked. And this div usually has a title. Here’s what the usage would look like:
1 2 3 |
<% hiding_div "Snazzy!" do %> Text and and a logo <%= image_tag "some_img.png" %> <% end %> |
Which should yield:
1 2 3 4 |
<div onclick="this.hide();"> <h2>Snazzy!</h2> Text and and a logo <img src="/images/some_img.png" /> </div> |