... ad kalendas graecas
'Todo el color del mar para tus ojos... Todo el agua del mar para mi llanto'



21/03/2007

Evitar el uso de ids en las URLs (Rails)

Cuando comencé a trastear con RubyOnRails, me encontré con que las URL’s que se generaban, contenían siempre el id del objeto sobre el que realizábamos la acción.
Así, por ejemplo, para mostrar una ciudad, la URL que se generaba con RoR “out of the box” y usando el script de scaffolding era: http://localhost:3000/city/show/1 donde 1 es el campo id de la tabla cities, campo que genera RoR por defecto y es autoincremental y clave primaria.

Ésto, como en todo, va en gustos, y a mi no me gustaba, así que busqué la forma de que ese 1 se sustituyera por el nombre de la ciudad, por ejemplo Madrid, que estábamos mostrando, editando, o lo que sea.

La forma más sencilla que he encontrado, y a falta de en el futuro encontrar otra forma o ver si da problemas, es la siguiente (partimos de una aplicación “limpia”, recién creada):

En la clase City (models/city.rb) escribiríamos lo siguiente, que lo único que hace es que cuando nos refiramos a un objeto city, sin referencia explícita a alguno de sus campos, en lugar de devolvernos el campo id que es lo que hace por defecto RoR, nos devuelva otro campo que queramos, en éste caso name:


def to_param
self.name
end

¿Por qué hay que hacerlo? Pues porque así todas las vistas generadas por el scaffolding siguen funcionando sin tener que cambiar ni una coma:
< %= link_to 'Show', :action => ’show’, :id => city %>
Es decir, en :id => city lo que nos devuelve ahora es el campo name, no el campo id. Si tuviéramos que cambiar la vista, habría que poner :id => city.name

Hecho ésto, ya todas las URL’s de nuestra aplicación se cambian como por arte de magia, y quedan tal que http://localhost:3000/city/show/Madrid si bien al hacer click en ellas no funcionan porque el controlador aún piensa que se le sigue pasando el campo id, cuando lo que ahora se le está pasando es el campo name.
Para que funcione el controlador, sólamente reemplazamos los .find(params[:id]) por .find_by_name(params[:id]) y listo. El parámetro :id ahora trae el campo name de la tabla, asi que por eso le decimos al find que busque por ese campo.

Ya sólo quedaría tener en cuenta que hay ciudades que no se podrían usar “tal cuál” en la URL. Por ejemplo: San Sebastián de los Reyes. Habría que pasarlas antes por un filtro para eliminar caracteres no válidos, sustituir los espacios por guiones, y, si quisiéramos, usar downcase para poner todo en minúsculas.
Yo en éste punto me inclino por crear dos campos en la BBDD. Uno para el nombre de la ciudad “en bruto” y otro para el nombre URL-friendly, es decir, con los caracteres extraños ya eliminados o sustituidos, y todo en minúsculas.
En el controlador, éste campo se rellenaría de forma invisible al usuario, al crear o modificar ciudades, a partir del nombre “en bruto” de dicha ciudad. Y se convertiría en clave primaria de facto, pues debe ser única para que nos sirva como sustituto real del campo id.

Delirio de Zheileman @ 11:50 | link permanente

Deja un comentario