Thursday, August 18, 2011

Stubbing out AJAX methods

I have always had trouble with the standard way of testing out AJAX calls with QUnit.

There are a number of problems with it.

1) You have to stop and start the tests while waiting for an AJAX response
2) If you don't give a large enough gap, then your test may fail while waiting for an AJAX response.
3) If you have too large a gap, it slows down your tests

However, today I found this cool method of dealing with it.

http://lostechies.com/johnteague/2009/02/10/another-way-to-test-ajax-methods/

Essentially, you stub out jQuery's $.ajax() method with your own for your tests (as for unit testing, you really just want to test your code around the ajax method, not test jQuery's ajax method).

In my own case, I was using $.ajax and not $.getJSON. It took me a little while to work out I had to create a trigger for the success() function rather then callback() as mentioned in the article.



var stubbedAjax = function(settings){
settings.beforeSend();
// so I can check error cases
if (settings.url == 'error'){
settings.error();
} else {
settings.success({data: "data"});
}
}
var originalAjax = jQuery.ajax;
module("WESTFIELD Product Index Aggregator",{setup:function(){jQuery.ajax = stubbedAjax}, teardown:function(){jQuery.ajax = originalAjax}});

Monday, July 18, 2011

Patterns

Just a couple of links today (more details to follow).

I found a great reference for JavaScript and jQuery Design Patterns here:

http://addyosmani.com/resources/essentialjsdesignpatterns/book/

Also, I learned about the Presenter pattern today. We were having a discussion at work about what to do with presentation logic in Rails. On the one hand you don't want it in the controller because you want to keep your controllers thin, on the other hand you don't want it in the models either because it's presentational. You can't put it in the erb because they shouldn't contain logic. Enter the Presenter Pattern:

http://donttrustthisguy.com/2008/05/29/using-presenters-in-rails-3/

http://blog.jayfields.com/2007/03/rails-presenter-pattern.html

Enjoy your homework!

Wednesday, July 06, 2011

What is !important?

In CSS, you can override a style on a class simply by declaring a new style further down the page

i.e.

p {
padding-top:5px;
}

p.custom {
padding:10px;
}

Basically the above code sets the padding-top on all paragraphs to 5px, but sets the padding to 10px on paragraphs with the "custom" class. So we are overriding padding on our custom class.

However, you can actually prevent an attribute's style from being overridden if for some reason you really really don't want the padding to change in your design. Perhaps you are working with multiple people and you really don't want someone to accidentally override your design. Perhaps you just want to ensure your padding-top is always 5px even if padding is reset somewhere else.

In order to do this we use !important.

p {
padding-top:5px !important;
}

p.custom {
padding:10px;
}

In this case, the padding-top on a paragraph will always stay at 5px regardless of whether or not it has a "custom" class. It will also stay at 5px if you do the following...

p {
padding-top:5px !important;
}

p.custom {
padding:10px;
padding-top:10px;
}

However all is not lost. Let's say you have imported someone else's CSS library and you want to tweak it but you find that they have used !important on the one style you want to update? Just use !important yourself...

p {
padding-top:5px !important;
}

p.custom {
padding:10px !important;
}

Yay! You can play in God mode too!

Of course in general it's best to avoid !important in every day situations. It's not really best practice, but it's there should you need it...

Sunday, May 15, 2011

The REAL reason you need Flash in a mobile device...

People keep going on about how you don't need Flash on a mobile device because most video sites like YouTube provide HTML 5 flash free versions. Therefore the limitation of no Flash on an iPhone isn't really a limitation (if you have been drinking Steve Jobs' Apple juice/kool aid).

Anyways, last Saturday I found out the REAL reason you need Flash on a mobile device and it has nothing to do with video.

It has to do with restaurant sites.

For some reason at least 80% of restaurants out there have Flash only websites. If you need to make a reservation and you can't find the phone number in Yelp or UrbanSpoon then you have a problem.

In any case, I was trying to find the number for a restaurant and Google gave me a link to their website. Unfortunately, their website is in Flash. Fortunately for me though, my phone is an Android phone and I was able to look up their phone number and address in spite of the limitation.

In general though, having Flash on a restaurant website is annoying. All I want is the address, phone number, a copy of the menu and a few pictures of the interior and the food. The ability to make reservations online is also a plus (not to mention online ordering if it's a take out restaurant).

PS In spite of their lousy Flash only website, I do really recommend the food at Anong Thai in Potts Point, Sydney. It is excellent!
http://www.anongthai.com.au/

Tuesday, May 10, 2011

CSS Back to basics: Here comes TRBL

So I guess CSS is not obvious to everyone. One of my coworkers asked today why you sometimes had 1 value after a "padding" attribute and sometimes you had 2 or 4 values.

Basically,


padding: 5px;

Puts a 5 pixel padding on an element.


padding: 5px 3px;

Means you have 5 pixels of padding on the top and bottom and 3 pixels on the sides


padding: 3px 4px 5px 10px;

Means you have 3 pixels of padding on top, 4 on the right, 5 on the bottom and 10 on the left.

A good way to remember this is the acronym TRBL (like "trouble").

The same applies to "margin".

As well as this, you also have extra attributes which can specify the top, bottom, right and left paddings on their own

i.e.

padding-left: 10px;


Sometimes, if only one side is unique, it's better to refer to it in the following way (for readability).


padding:5px;
padding-left: 10px;

The "padding-left" of 10px will override the "padding" of 5px, but only on the left side of the element.


padding: 5px 5px 5px 10px;

The above does the same, but is less readable in my opinion.

Thursday, April 28, 2011

Rails file uploads: Limiting a user's uploads by space available

Let's say that you want to allow people to upload files to your server. Let's also say that we want to make sure any particular user does not hog up all the space available. Let's also say you want to give each user a variable limit as to how much they can upload (i.e. for tiered services). How would you go about doing that?

Well, from a pseudo code perspective you would do the following.

1) Create a folder for each user based on the user id
2) Make sure all the user's uploads go to that folder
3) Before you do an upload, check against the user's settings to see how much space s/he is allowed
4) Check their folder to see how much space has been used
5) If they have no space left, message the user

So let's see how we do this in practice...

I guess we really want to see how much space is used, so let's start there on the User. In this example the user has a UUID as well as a space_allowed attribute which is set to a default value (and which an admin can change).


def space_used
space = 0
directory = "#{Rails.root}/uploads/#{self.user.uuid}"

if File.directory?(directory)
Find.find(directory) { |f|
space += File.size(f);
}
end
return space
end


So space_used first sets the directory based on the user's uuid. It then checks to see if that directory exists, and if it does, it will loop through each file and total up the space variable (unfortunately, the Directory object does not have a size variable) to see how much space has been used.


def space_available?
if self.space_used >= self.space_allowed
return false
end
return true
end


space_available? checks the space used and compares it to the space_allowed to the user. So in the controller you just need to call space_available? on the user and handle it appropriately

i.e.


user = User.find(params[:id])
if user.space_available?
... handle upload ...
else
... handle error ...
end

Reading AJAX XHR File Uploads in Sinatra

So in my last post I talked about Drag and Drop file uploading with qq.FileUploader (http://valums.com/ajax-upload/).

Anyways, I discovered that qq.FileUploader uses AJAX/XHR to post the file uploads. What I also discovered is that these file uploads need to be handled in a separate manner from a regular file upload form post.

A normal form post (when File upload XHR requests are not available on the client like in Internet Explorer) passes in the following parameters


params: {"qqfile"=>{:type=>"image/png", :head=>"Content-Disposition: form-data; name=\"qqfile\"; filename=\"bb2.png\"\r\nContent-Type: image/png\r\n", :tempfile=>#, :name=>"qqfile", :filename=>"bb2.png"}, "upload_type"=>"rec", "id"=>"24db8cab-285a-abcb-cb47-4daceee977ca"}

Sinatra then reads the :tempfile and :filename parameters to write the file to the server


name = params[:qqfile][:filename]

# create the file path
path = File.join(directory, name)
# write the file
File.open(path, "wb") { |f| f.write(params[:qqfile][:tempfile].read) }


However, if you use a browser that supports XHR uploads, the parameters look a little different


params: {"qqfile"=>"device1.jpg", "upload_type"=>"invoice", "id"=>"24db8cab-285a-abcb-cb47-4daceee977ca"}

So this had me stumped. There was an article I found on the internets (http://onehub.com/blog/posts/designing-an-html5-drag-drop-file-uploader-using-sinatra-and-jquery-part-1/) which talked extensively on how to do the JavaScript side but then at the bottom conveniently left out how to handle the server side (saying it was easy to work out). Well, it wasn't! So that's why I am writing this post

In any case, I won't keep you in suspense any longer...


name = env['HTTP_X_FILENAME']

string_io = request.body # will return a StringIO

data_bytes = string_io.read # read the stream as bytes

# create the file path
path = File.join(directory, name)

# Write it to disk...
File.open(path, 'w') {|f| f.write(data_bytes) }


The final part is that qq.FileUploader does not give you the option to specify which action to post to depending on the type of upload (XHR vs normal) so I had to put in a fork in the server code to figure out how to handle the request. I am basically checking to see if qqfile is of type String, in which case I handle it as an XHR upload, otherwise I handle it as a normal file upload.


# if qqfile is a string, we are using XHR upload, else use regular upload
if params[:qqfile].class == String
name = params[:qqfile]

string_io = request.body # will return a StringIO

data_bytes = string_io.read # read the stream as bytes

# create the file path
path = File.join(directory, name)

# Write it to disk...
File.open(path, 'w') {|f| f.write(data_bytes) }
else #regular file upload
name = params[:qqfile][:filename]

# create the file path
path = File.join(directory, name)
# write the file
File.open(path, "wb") { |f| f.write(params[:qqfile][:tempfile].read) }
end


I haven't tried it in Rails yet, but I am sure it will be similar. I hope this helps...

Wednesday, April 27, 2011

Ajax File Uploading

You know that cool Drag and Drop file uploading they have in Gmail? You know, the one where you can drag a file from a folder onto a webpage and upload it?

Have you looked at the code? Looks complicated huh?

Well, thankfully, for any cool bit of JavaScript functionality out there, someone has created a plug in (most likely in jQuery, but not always...).

http://valums.com/ajax-upload/ is (as far as I can tell) a library agnostic JavaScript plug in which factors out all the hard work.

All you have to do is put in a "dummy" element on to which to hook (never end a sentence in a preposition) and then put in a small snippet of code to turn it into a file upload element


<div id="file-uploader">
<noscript>
<p>Please enable JavaScript to use file uploader.</p>
</noscript>
</div>


var uploader = new qq.FileUploader({
// pass the dom node (ex. $(selector)[0] for jQuery users)
element: document.getElementById('file-uploader'),
// path to server-side upload script
action: '/server/upload'
});

Obviously you need to include their library as well...

It has some common backend code to handle uploads as well (php, perl, cgi, java) but no Ruby. Come on guys! Get with it already! Hopefully they will read this and provide...

Tuesday, April 26, 2011

Node.js

I had a quick look at Node.js. Looks very interesting (kind of like a JavaScript version of Sinatra). Now all I need to do is find out if they have any frameworks...

Wednesday, April 20, 2011

Show Off IO

Just found a great new service called Show Off IO

https://showoff.io/

This is a godsend for Ruby contractors. Basically you port forward the web server on your laptop to showoff and they give you a URL which you can send to a client which allows him to see your website (for a limited time for the free version).

Previous to this, you would have to wait until you had staged the site to show it to your clients.

Good job guys!

RhoMobile - Ruby Development for Mobile

RhoMobile (http://rhomobile.com/) offers an open source framework which allows Ruby developers to write mobile apps using web technologies.

I have been using it for about a year now. You can find out the details of it on the website linked above, but I just wanted to go over some of the issues I have found and cover some of the pluses in minuses from a personal perspective to help you decide whether or not this is a technology you will want to exploit on your next project.

So what is it?

At a basic level, a Rhodes (http://rhomobile.com/products/rhodes/) app comprises of a small Ruby web server/framework and an embedded browser. Server is a little bit of a misnomer because it lives on the client, but essentially it's like a small Rails server which is only used by one client (though in theory you can connect to it from another client if you so choose).

Because the display is done in an embedded browser, you can mark it up in HTML and CSS and even (in some cases) use JavaScript to manipulate the display dynamically.

So why use Rhodes instead of creating a mobile web app?

Well, for one, you can package a Rhodes app and sell it in the app store, android market or app world.

It also (if you need it to) can sync with a sophisticated sync server known as RhoSync (http://rhomobile.com/products/rhosync/). As of the time of writing, RhoSync is built upon Sinatra and Redis (it used to be Rails and MySQL). This means that a user can manage and manipulate his/her data on their phone without the need for a constant internet connection and that data can be periodically synced with the back end. RhoSync manages all the potential data conflicts and only syncs the differences. It can connect to practically any kind of data store (databases, REST APIs, etc...).

So what are some of the limitations of Rhodes?

So, unfortunately, nothing in life is perfect. One limitation is that because it relies on embedded browsers, if your app does any fancy JavaScript or CSS3 you will have to write another set of HTML only views for BlackBerry (though apparently the latest BlackBerry versions use a WebKit browser. I have yet to try this personally though).

It also really is targeted at the high end smart phones. It is quite well optimised for iOS, but on slower Android devices (anything with less than a 600Mhz processor) it can be quite slow and sluggish.

Another thing to get one's head around is that even though the framework is Rails-like, it is not exactly the same as Rails (it is quite stripped down). The RhoMobile team have been busy adding features however so its ecosystem is growing. When I started using it, there were no models (only controllers and views). Since then, Model support has been added as well as MSpec for testing.

Once your product is done, adding it to the respective app markets is also quite a hassle. This is by no means the fault of RhoMobile or the Rhodes team, but it is something to consider when trying to decide between doing a web based app vs an installable one.

The other limitation is because Rhodes is designed to work with most of the major smart phones on the market, you haven't got access to all the available features on a specific mobile phone. There is limited camera and calendar support, but currently no audio or video recording (it's in the road map, but not yet available). So you are not going to be able to write an app like Shazam or Google Maps using the framework...

Conclusion
If you like Ruby, web technologies AND mobile apps then it's definitely worth taking a look at RhoMobile. It's especially suited for Enterprise App development where you may not need the latest fancy UI enhancements, but you do want to deploy on all the platforms that your team is using with a single code base.

More References

You can find more information on the app I developed at
http://rhologic.com/

Responsive Web Design

I wanted to go over Responsive Web Design using CSS.

In the old days of web development, we had to code to common screen sizes (i.e. 800 X 600, 1024 X 768) and we patiently waited for people to upgrade their computers to have a decent amount of screen real estate so we could design things the way we really wanted. We also took on semi stretchy web layouts etc to expand and contract appropriately.

Then about 2 or 3 years ago, Apple released this little device called an iPhone with a 320 X 480 resolution which took the world by storm and suddenly a lot of people were viewing your website on a tiny screen again...

Anyways, as it can be difficult to design a site which looks good on 320 X 480 AND 1680 X 1050, we need to come up with some kind of solution.

One way is to sniff the client and then use an appropriate stylesheet, but then you are mixing CSS with either JavaScript or server side programming and also potentially maintaining a list of appropriate clients and stylesheets. Also, you can miss out new devices/clients as they come along.

The other way is to use the media queries and detect the screen size using CSS.

i.e.

@media screen and (max-device-width: 480px), screen and (max-width: 480px) {
...
appropriate iPhone/Android CSS rules go here
...
}

You can also "detect" for iPad by using 768 instead of 480.

Things to look out for
I found that although it is possible to move elements around using CSS, there are some limitations with regards to content flow. In one design that I was given by my designer, the logo was to move from the middle to the top of the page depending on the device. What I ended up doing was creating 2 logos and hid/showed them appropriately.

It also helps to break the page down to standard elements (main content, header, footer, etc...) and focus on designing/laying out these elements appropriately. Once you are done with that, you are 80% of the way there and you might only need to do some minor tweaking of the main content section thereafter (i.e. moving form labels from the side to the top for example).

It is important to know your audience as well. In my case, this time around, I am working on a site which is an adjunct to a phone app and it is important for our audience to be able to view the site well on a phone as well as a full size computer. This does involve extra work so there may not be any business to justify it in your case.

Further links
http://www.alistapart.com/articles/responsive-web-design/
http://mediaqueri.es/