Subscribe to my Feed, follow me on Twitter, recommend me on Working With Rails or see my code on GitHub
Prototype-based inheritance in Ruby
This was originally posted as a response to a “challenge” on irb.no, and I thought it was kind of clever, so I’ll post it here as well ;) The challenge was to write something object-oriented in Ruby without using classes. So, inspired by my recent crush on ECMAScript, I thought, why not try to implement prototype-based inheritance in Ruby?
Object.class_eval{ attr_accessor :prototype }
Object.class_eval do
def method_missing(s, *a)
if self.prototype.nil?
raise NoMethodError, "LOL U MISSING #{s}!!"
else
self.prototype.send(s, *a)
end
end
end
cat = Object.new
def cat.meow; 'IM IN UR OBJECTZ'; end
cat.meow # => "IM IN UR OBJECTZ"
kitten = Object.new
kitten.prototype = cat
kitten.meow # => "IM IN UR OBJECTZ"
(Yes, a bit of LOLCODE inspiration there too)
I’m sure this has been done by many before me, because it’s so simple. And that’s what I like about it. The implementation is simple beause the concept is simple. Simplicity beats complexity any day.
Meet Sanskrit, the Rich Textile Editor
Sanskrit is a simple “rich-text editor” with no bells or whistles, and it outputs Textile instead of XHTML. It’s meant to be safe (with regards to XSS, hence Textile) and simple. It only works with the most basic (inline) text styles.
This is my very first time writing something that resembles a library in JavaScript, so it’s probably full of bad practises, errors and generally smelly code. If you have tips for improvement, please let me know. I’ve tested this in Gecko, IE6, IE7, Opera 9 and Konqueror (which doesn’t support this kind of stuff, but the fallback to a normal textarea works), but if you find that it doesn’t work in a browser (and preferrably how to fix it :), please let me know about that too.
Internet Explorer 7, I accept your presence
If you’re into self-afflicted pain and use Internet Explorer 7 you should now get this page as HTML instead of X(HT)ML. I recently found out that IE7’s Accept header consists of nothing but */*, which means it supports every type of document there is. Then I found out that’s not actually true, so HTML is now the default unless your browser asks for something else, like XHTML.
The CSS probably doesn’t work in IE, so everything is probably out of place. I couldn’t care less.
IRB for JavaScript
Have you ever wished there was a console application for JavaScript, like IRB for Ruby, where you can try things out? Well, there is one and it is part of Mozilla’s SpiderMonkey JavaScript implementation (in C). If you’re on Ubuntu (and maybe Debian too?), installing it is as easy as
apt-get install spidermonkey-bin
Then, run js:
js> Foo = function(){}
function () {
}
js> Foo.prototype.bar = function(){ print('BAR!') }
function () {
print("BAR!");
}
js> foo = new Foo()
[object Object]
js> foo.bar()
BAR!
This may be something that everyone else but me knew about, but I’m pretty excited to have somewhere other than a browser to try out things as I start learning JavaScript properly.
New SVN address/domain troubles
I’ve been having some domain troubles lately, so if you’ve been using one of my plug-ins with svn:external or trying to install one in a new project Subversion probably complained about not being able to look up the domain svn.2750flesk.com. I’ve moved the plug-ins to
http://nimrod.interinter.net/plugins/
Sorry for any inconvenience this might have caused, such as messing up a streamlined Capistrano deployment process :)
Cleaning up your nest: How to nest resources with multiple access points
With Rails’ new routes nesting resources is easy. Now, whether you should nest or not depends on a lot of things, and others have written smart things about that. Sometimes though, nesting makes sense, and sometimes resources can have multiple access points. In REST terminology, they’re actually different resources, even though in Rails they use the same model. A classic example is this:
class User < ActiveRecord::Base
has_many :posts
end
class Category < ActiveRecord::Base
has_many :posts
end
class Post < ActiveRecord::Base
belongs_to :user
belongs_to :category
end
Here, it makes sense to list posts in a certain category and posts that are written by a certain user in addition to just listing all posts. But how do you represent this in a RESTful manner in Rails? The basic assumption seems to be that a controller maps to a model, but I don’t think that’s the best way to do it. If you have multiple resources that use the same model, how would you know in which context the controller is used? For
PostsController in this example, how would you limit the posts listed based on a user or a category? Sure, it’s doable, but it can get pretty messy. Instead, I suggest thinking of a controller as a resource access point. That is, controllers map to resources. So, in this example, we would have a separate controller for each of these resources:
#/posts
class PostsController < ApplicationController
def index
@posts = Post.find(:all)
end
end
#/category/:category_id/posts
class CategoryPostsController < ApplicationController
before_filter :find_category
def index
@posts = @category.posts
end
private
def find_category
@category = Category.find(params[:category_id])
end
end
#/users/:user_id/posts
class UserPostsController < ApplicationController
before_filter :find_user
def index
@posts = @user.posts
end
private
def find_user
@user = User.find(params[:user_id])
end
end
Then we map all the resources in routes.rb, specifying which controller to use for the nested resources. We also add a
:name_prefix to the nested resources so the names don’t clash with the other resources with the same name.
ActionController::Routing::Routes.draw do |map|
map.resources :posts
map.resources :users do |user|
user.resources :posts, :controller => 'user_posts', :name_prefix => 'user_'
end
map.resources :categories do |category|
category.resources :posts, :controller => 'category_posts', :name_prefix => 'category_'
end
end
But that’s not DRY
There’s a lot of repetition here, but who cares? The controllers have clearly separated concerns because they represent different resources. For
UserPostsController you may not want to show a single post for example, but instead, in /user/:user_id/posts, point to /posts/:id. Repeating yourself is much better than getting tangled up in increasingly complex abstractions.
