format internet:

…please wait (42% completed)…

rails,ajax,charset (ii)

Posted by javier ramirez on December 3, 2006

Como veíamos aquí cuando utilizamos ajax y rails tenemos que ser cuidadosos si queremos usar un juego de caracteres distinto a UTF-8. Ya hemos resuelto cómo mostrar correctamente la información que traemos desde el servidor, pero todavía tenemos que resolver cómo enviarla correctamente.

Cuando usamos los helpers de rails, las llamadas ajax funcionan enviando la información al servidor serializada mediante la función “serialize” definida en prototype.js. Esta función a su vez utiliza por debajo la llamada a la función javascript estándar “encodeURIComponent”. Por último, esta función hace un encoding pasando primero del charset que tenga la página a UTF-8 y luego escapando los caracteres.

Como resultado, cualquier llamada vía ajax que hagamos a través de prototype.js va a llegar al servidor con los parámetros en UTF-8. Una vez conscientes de este mecanismo, la forma de solucionarlo es simplemente convertir cada parámetro que recibamos en el servidor al encoding deseado, para lo que podemos usar Iconv.

Para evitar tener que pasar cada parámetro al encoding deseado, podemos hacer algo mucho más simple, consistente en convertir todos los parámetros del objeto “params”, de forma que no tenemos que andar en cada acción discriminando qué tenemos que convertir y qué no. Obviamente esto lo haremos solamente cuando detectemos que la llamada se hizo vía ajax.

Para mayor comodidad, lo que he hecho en mi caso es definir una función nueva llamada “iconv”, para la clase Hash, que directamente me recorre una Hash y todos sus hijos (siempre que soporten el método iconv), convirtiendo todas las cadenas que encuentra al encoding deseado. El código necesario para esto lo muestro a continuación:

class Hash
  #converts the encoding of all the values in the (can be nested) hash,by using iconv
  def iconv(c_to,c_from,obj_iconv=nil)
    obj_iconv = obj_iconv || Iconv.new(c_to,c_from )
    self.each do |key,value|
      next if value.blank?
      if value.is_a? String
        self[key] = obj_iconv.iconv(value)
      elsif value.respond_to? ‘iconv’
        self[key] = value.iconv(c_to,c_from,obj_iconv)
      end
    end
    return self
  end
end

Este código convertirá las Strings (y las Strings dentro de una Hash) que encuentre en el objeto que se le pase. Normalmente no necesitaremos nada más, pero si fuera necesario implementar la funcionalidad para Arrays u otros objetos, sería trivial definir un método “iconv” que los recorra de forma análoga al mostrado.

Ahora ya todo lo que tenemos que hacer es definir un filtro para todas nuestras acciones o bien escribir al principio de cada una el siguiente código

  params.iconv(‘iso-8859-1′,’utf-8’) if request.xhr?

Y ya podemos ser felices escribiendo y aceptando cadenas en nuestro propio idioma.

searchwords: charset, utf-8, iso-8859-1, iconv, prototype.js, javascript, encodeURIComponent, ajax

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: