Subscribe to my Feed, follow me on Twitter, recommend me on Working With Rails or see my code on GitHub
Scope in JavaScript
I wrote this article a few weeks ago as a part of JavaScript Eye for the Ruby Guy but have forgotten to publish it.. So, here it is:
It’s not very long, because scope in JavaScript is really simple once you know how it works.
FormHelper
An unobtrusive "unobtrusive" answer to the very frequently asked question “how do I create a dropdown that fills out another dropdown”.
<select name="foo" class="updates:bar">
<option value="1">1</option>
<option value="2">2</option>
</select>
<select name="bar">
<optgroup label="1" class="foo:1">
<option value="1">1.1</option>
<option value="2">1.2</option>
</optgroup>
<optgroup label="2" class="foo:2">
<option value="3">2.1</option>
<option value="4">2.2</option>
</optgroup>
</select>
And it just works.
Download now for the low price of nothing and get one extra feature for no added cost! But wait, there’s more! Download within the next ten years and receive the practical Checker for free!
New
I always thought new Class was too much like Java..
Function.prototype.new = function(){
function F(){};
F.prototype = this.prototype;
var o = new F();
this.apply(o, arguments);
return o;
};
function Cat (name) {
this.name = name;
};
Cat.prototype.greet = function(){
return "Hello, my name is " + this.name;
};
var garfield = Cat.new("Garfield");
garfield.greet(); // "Hello, my name is Garfield"
Just like Ruby! I know, I know, “new” is a reserved word.. For some reason it works just fine in Firefox, but you can just as well call it “create” or “spawn”, or “beget”. I’m sure it’s still a pretty bad idea to begin with, and I can’t see any advantages at all with it. It’s just that I have a strong dislike for keywords.
JavaScript Eye for the Ruby Guy
A while ago a number of articles were written under the common name Ruby Eye for the Java Guy, which explained Ruby from a Java programmer’s point of view. I’ve been meaning to do the same for JavaScript for a while, explaining JavaScript from a Ruby programmer’s point of view, but I kept, ehm, not doing it. I finally got around to writing it this weekend though, and I’ve put it up here:
JavaScript Eye for the Ruby Guy
As good as every Ruby programmer who uses Rails also uses JavaScript, but not many actually know how it works. I used to only care enough to make it work and dismissed JavaScript as unimportant, but I’ve since learnt how wrong I was. Many like me are starting to see it for what it really is – a little quirky but at the same time a fascinating and powerful language. There is currently a big drive towards using more unobtrusive JavaScript and Ajax techniques in web pages, and knowing how to actually program in JavaScript is definitely an advantage :)
The article is by no means comprehensive, but it should explain the most basic (and most interesting) stuff.
Sanskrit updates
(Sanskrit is the Rich Textile Editor)
I’ve been tweaking Sanskrit the last few days, as it used to have some problems. It used to be kind of flaky in Gecko because of a (not so) weird problem with dynamically inserting iframes. Turns out I had to make it wait a little bit longer in order for Gecko to initialise the iframe document before working with it, which I was hesitant to do at first because it makes it seem less lightweight. I’ve also added a “textile” menu button which will let you edit the Textile directly, much like traditional WYSIWYG editors like TinyMCE will let you edit HTML. All in all, it should be a bit more solid now, and might actually be considered fit for production :)
routes.js update
I’ve made a few changes to the JavascriptRoutes plugin to make it Even Betterâ„¢. One of those changes is to check hasOwnProperty on parameters and options, and it has made it clear to me how important it is to not mess around with Object.prototype (or, make sure an object’s properties don’t come from somewhere in the prototype chain).
Before:
Object.prototype.iThinkEveryObjectShouldHaveThis = 'for sure';
Routes.generate({controller:'lolcats', action:'show', id:1}, {onlyPath:true})
// => "/lolcats/1?iThinkEveryObjectShouldHaveThis=for%20sure"
Now:
Object.prototype.iThinkEveryObjectShouldHaveThis = 'for sure';
Routes.generate({controller:'lolcats', action:'show', id:1}, {onlyPath:true})
// => "/lolcats/1"
This also means the plugin won’t work in browsers that don’t have the hasOwnProperty method. Those that I know of that don’t have this are Safari 1.3 and IE 5.0. It also uses try-catch, which was only introduced in JavaScript 1.5. If enough people complain, I might try to change this.
routes.js, episode two: The Plugin
Now with all routes created equal (not just named routes anymore).
It turns out replicating Rails’ route generation in JavaScript wasn’t trivial, but it was definitely doable and it seems to work pretty well too. I’ve packaged it up in a plugin for easy consumption. Read more about it here.
Routes.generate({controller:'foo', action:'bar', id:'baz'})
Routes.page(1)
Routes.blog_entry_comment(1, 2)
Routes.page({id:42}, {onlyPath:true, escape:false})
Routes.generate({controller:'rabbits', rabid:'yes'})
You can test the route generation “live” here, or if you have FireBug installed, just use that.
ActsAsMonkey, a sample Rails plugin
After seeing a lot of people ask for information on writing plugins to Rails, I wrote a sample plugin so people could take a peek inside and see how it’s built. It may not be the World’s Best Plugin, and you can see how any plugin is built, but it should cover the basics, and I’ve tried to comment it where (I think is) necessary.
More here.
ActsAsFile: Simple file storage plugin
ActsAsFile will save files attached to a model in a specified directory on the file system. It will add validation errors on the model if the file can’t be saved. And.. I think that’s it. As I said, it’s simple, and I like simple. Read more about it here.
class UploadedFile < ActiveRecord::Base
acts_as_file
self.save_path = File.join(RAILS_ROOT, 'public', 'uploads')
self.read_path = 'uploads'
end
routes.js
Update: I’ve put this in a plugin which also includes non-named routes, here.
If you’re writing unobtrusive JavaScript with Rails, figuring out URLs can sometimes be a bit of a show stopper. I’ve hard-coded URLs into my JS files more than once, and that smells. Wouldn’t it be just terrific if we could access Rails’ routes in JavaScript? Well, it turns out that’s not so difficult to achieve. Just put this in environment.rb:
File.open(File.join(RAILS_ROOT, 'public', 'javascripts', 'routes.js'), 'w') do |file|
file << "var Routes = {\n"
ActionController::Routing::Routes.named_routes.routes.each do |name, route|
dynamic_segments = route.segments.select{|s| s.respond_to?(:key) }
file << " #{name}: function(#{dynamic_segments.map(&:key).join(', ')}) {\n"
file << " return '"
route.segments.each do |segment|
if segment.respond_to?(:key)
file << "'+#{segment.key}+'"
else
file << segment.to_s
end
end
file << "';\n"
file << " },\n\n"
end
file << "};"
end
It only works for named routes, but if you’re RESTful that should be enough. Getting “normal” routes in there should be possible, but it basically means you’d have to replicate the route recognition generation system in JavaScript, which I think would be non-trivial.
How to use it? Well, first of all, include routes.js:
<script src="/javascripts/routes.js" type="text/javascript"></script>
All the named routes will be defined as functions on the Routes object, and each function takes 0 or more parameters. They work pretty much like the generated helper methods in Rails. Let’s say we have these routes defined in routes.rb:
map.resources :articles
map.home '', :controller => 'main'
To generate the URLs in JavaScript, we’d use:
Routes.articles() // => "/articles/"
Routes.article(1) // => "/article/1"
Routes.home() // => "/"
