Cuando se trabaja en cualquier aplicación de Rails que no sea un simple "Hola mundo", inevitablemente se necesitan pequeños ayudantes AJAX para comunicarse con el servidor y realizar lógica del lado del cliente. No me refiero a una API en sí, sino a utilidades ad-hoc como esta:
markdown.change(function(){
generate_html_on_the_server( markdown.val(), function(html){
preview.html(html);
});
});
o
reservation.change(function(){
check_availibity_on_the_server( reservation.val(), function(data){
if(!data['available']){
alert('ese tiempo no está disponible - elige otro!');
};
})
});
etc.
Este tipo de funciones no forman parte de una API pública de servidor a servidor, son simplemente puntos finales de cooperación js/backend que son necesarios para que funcione la vista.
La mayoría de las aplicaciones de Rails acumularán muchas de estas y surge la pregunta:
“¿Dónde las pones?”
En la mayoría de los equipos, tendrás tres o cuatro desarrolladores nombrando y organizando estas funciones de diferentes maneras, asegurando que la base de código se convierta en un desorden de espagueti vaquero en poco tiempo.
@dojo4 hemos abstraído esto con un pequeño patrón de diseño rpc: primero tenemos un pequeño dsl de controlador que se incluye en nuestro ApplicationController que permite definiciones declarativas de ayudantes js 'rpc' por controlador.
class ApplicationController < ActionController::Base
include(RPC)
end
Consulta la implementación aquí: https://gist.github.com/ahoward/7320900
En inglés sencillo, este dsl simplemente define una única acción en el controlador que multiplexa qué método emplear en función de los parámetros y una forma fácil de definirlos. Espera que todas las acciones rpc devuelvan un hash y proporcionen json.
Su implementación se reduce a
def rpc
which = params['method']
action = @rpc[which]
result = action.call(params)
render :json => result.to_json
end
Su uso debería ser obvio a partir del código
class GeoLocationController < ApplicationController
rpc(:geo_location) do |params|
geo_location = GeoLocation.geo_locate( params['address'] )
geo_location.attributes
end
rpc(:lat_lng) do |params|
geo_location = GeoLocation.geo_locate( params['address'] )
{ 'lat' => geo_location.lat, 'lng' => geo_location.lng }
end