On Thu, Nov 15, 2007 at 08:26:47PM -0600, Michael D. Ivey wrote:
> # Scenario:
> # You have a simple application that lists all the monkeys at the zoo.
> # Every monkey has a name, and that name is unique.
> # It is currently working.
Presumably it also has something like
def index
@monkeys = Monkey.find(:all)
end
> # Your boss comes and asks you to change the "ugly" /monkeys/44 URLs
> # to be "pretty" and "SEO optimized" URLs like /monkeys/koko, with the
> # monkey's name in the URL.
> #
> # Challenge:
> # Design your perfect API for doing this
What do you mean by 'API' here? Or is the idea to explore all the
possibilities which might be implied?
As far as I can see:
(1) you could use an ORM which permits use of an arbitrary field
as the primary key; in this case only the model would need to change.
class Monkey < MythicalORM
self.primary_key = 'name'
end
(In the case of ActiveRecord, I believe that non-integer ID fields are not
supported. Also, if you intend retaining the old integer 'id' column in
parallel with the monkey name primary key, beware that AR may no longer
generate the next integer id for you automatically, so you may need to do
this explicitly in a before_create hook)
(2) modify Merb so the url() helper can use an arbitrary model field as the
resource id, e.g.
r.resources :monkeys, :resource_id => :name
class Monkeys < Application
def show(id)
@monkey = Monkey.find_by_name(id) || (raise "No such monkey")
end
end
The :resource_id is used by the url() helper to pick the correct attribute
to put into the URL.
But if the idea is to add some feature to Merb for this, I would suggest
first a generalisation of the problem to allow for composite primary keys.
e.g. if each monkey has a first name and last name, and the tuple (first
name, last name) is unique, then allow resource URLs of the form
/monkeys/koko/pops
or /monkeys/koko;pops
This introduces further difficulties (*), but is realistic when wanting to
map a web application onto an existing schema which was designed in this
way.
(*) in particular: the database may have primary key tuples of the form
("","foo") and/or (null,"foo")
> # Don't complain that doing /monkeys/koko is dumb, or what happens
> # when there are two monkeys named koko
Or what happens when a monkey's name contains a forward slash. (If you
replace monkeys with car parts, IDs of the form xxx/yyy are not uncommon;
with Rails at least, even encoding as %2F is treated as a path separator)
Which reminds me of: http://xkcd.com/327/
Incidentally, when I wanted to do something similar to this in a Rails app,
I ended up using URLs of the form /monkeys?name=koko
Then if a single monkey matches, I redirect to /monkeys/44; if multiple
monkeys match, I list them. Something like this:
MAX_RESULT = 10
def index
if params[:name]
@monkeys = Monkey.find(:all, :conditions=>['name=?',params[:name]],
:limit => MAX_RESULT, :order => 'name')
render_monkeys('Monkeys by name')
else
@monkeys = Monkey.find(:all)
end
end
def render_monkeys(title = 'Monkeys')
@title = title
if @monkeys.size == 1
redirect_to monkey_url(@monkeys.first)
elsif @monkey.size == 0
flash.now[:notice] = 'Monkey not found'
else if @monkeys.size == MAX_RESULT
flash.now[:notice] = "Only the first #{MAX_RESULT} monkeys shown"
end
end
You can extend the 'if' statement in index to allow for other ways of
referring to the monkey, e.g. /monkeys?asset_tag=12345.
Now, this suggests a question back to the boss: after the proposed change of
URLs, what happens if you want to fetch a monkey given its original ID of
44?
Would we need to provide a second URL of the form /monkeys?id=44 ? Or will
the old ID just become a normal data attribute? Or is this change of
"primary key" going to be so pervasive that we will delete the old id column
from the database entirely?
If multiple 'primary keys' are to be exposed, you could argue that this
should be done orthogonally, e.g.
/monkeys/id/44
/monkeys/name/koko
/monkeys/asset_tag/12345
But this still begs the question of which form will be generated by the
url() helper. So ultimately one of these is going to take precedence over
all the others.
Regards,
Brian.
_______________________________________________
Merb-devel mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/merb-devel