Recorrer hash por orden?

Buenas, me ha surgido una duda.

Tengo un controlador que genera consultas dinámicas y las busca con
find_by_sql. Es decir, que pasando por el mismo controlador, puede pasar
la
consutlta select login from usuarios y select login, password from
usuarios.

El caso es que para dibujar la tabla de resultados, en caso de que la
consulta haya devuelto más de un resultado, se recorren las claves del
hash
devuelto en el primer resultado así:

@items_pages, @items, @total = paginate_by_sql Usuarios, query,
items_per_page
@columnas = @items.size>0 ? @items[0].attributes.keys: []

Entonces ya tengo las columnas para poder iterar sobre ellas y mostrar
los
resultados. Lo hago así en la vista:

<%if @items.size==0%>


No hay elementos
<%end%>
<% @items.each do |objeto| %>
<tr class=“record <%= cycle(”",“even-record”) %>">
<%for columna in @columnas%>
<%= objeto.attributes[columna]%>
<%end%>

<% end %>

El problema es que me suelta las columnas con un orden no demasiado
lógico.
Si yo quiero que me muestre primero el login y luego el password, me lo
muestra al revés. Y cuando ya son 7 u 8 columnas, la liamos todavía más.

¿Cómo podría hacer para que me recorriese las columnas “ordenadamente”?

Muchas gracias
Un saludo

Hola Luis,

Para eso te recomendaría la clase SequencedHash incluida en la gema
collections. Funciona como las Hash de ruby pero mantiene ordenados los
elementos:

http://collections.rubyforge.org/

Saludos,
Raul M.

Ahí ando un poco perdido. ¿Cómo lo utilizaría? porque el método
find_by_sql
rellena el @attributes del modelo, que es un hash.

¿Tendría que sobreescribir la clase Hash? ¿Cómo se haría?

Ahí ando un poco perdido. ¿Cómo lo utilizaría? porque el método
find_by_sql rellena el @attributes del modelo, que es un hash.
¿Tendría que sobreescribir la clase Hash? ¿Cómo se haría?

A riesgo de parecer tonto… es necesario el segundo bucle?

Por que no en vez de esto:

<%if @items.size==0% >


No hay elementos
<%end%>
<% @items.each do |objeto| %>
<tr class=“record <%= cycle(”",“even-record”) %>">
<%for columna in @columnas%>
<%= objeto.attributes[columna]%>
<%end%>

<% end %>

No haces…

<%if @items.size==0% >


No hay elementos
<%end%>
<% @items.each do |objeto| %>
<tr class=“record <%= cycle(”",“even-record”) %>">
<%= objeto.atributo_1%> # O también <%=
objeto[:atributo_1] %>
<%= objeto.atributo_2%>
[…]
<%= objeto.atributo_n%>

<% end %>

Vamos… yo le dejaría el orden a la vista

No, las consultas las mete el administrador en un text area y la
aplicación
se encarga de añadirle las condiciones y tal. Pero es el administrador
el
que mete el código sql tal cual.

Es como un generador de reportes (más o menos)

Es porque las consultas las genera una persona. Igual puede poner select
perros from usuarios que select casas from usuarios, así que de antemano
yo
no voy a saber qué columnas son las que van a salir.

No sé si la forma en que lo hago es la mejor, pero no se me ocurre otra.

Gracias de todas formas por el interés

Luis V.
escribió:> Es porque las consultas las genera una persona. Igual puede poner select

perros from usuarios que select casas from usuarios, así que de antemano
yo no voy a saber qué columnas son las que van a salir.

Las consultas se generan al vuelo? Es decir, tú das en tu interfaz la
opción de indicar qué columnas se desean consultar? En ese caso podrías
almacenar esas columnas en una SequencedHash @columnas, generar a partir
de ella la consulta y utilizarla en la vista para determinar el orden en
que se muestran los datos.

Hola

No, las consultas las mete el administrador en un text area y la
aplicación se encarga de añadirle las condiciones y tal. Pero es el
administrador el que mete el código sql tal cual.

Es como un generador de reportes (más o menos)
yo una vez tuve que hacer algo parecido… un generador en el que el
usuario podía meter la consulta en la aplicación y le generaba un excel
con la respuesta, y lo que acabé haciendo fue una solución más o menos
simple. Tomaba el sql que me pedían lanzar, me quedaba con el texto que
aparecía entre “SELECT y FROM” y ese texto lo separaba por comas para
saber cuáles eran las columnas que me pedían.

Como sabes, en una select se pueden meter muchas filigranas, funciones
agregadas, claúsulas AS, etc… Si quieres hacer un parser capaz de
tragarse todo eso y que además sea multidb, suerte… yo consulté con mi
usuario para saber qué tipo de selects iban a usar y poder así parsear
la lista de columnas. Si las selects van a ser sencillas, lo mismo te
vale con separar por comas, comprobar si hay un AS y si no directamente
tomar el nombre de la columna.

Una vez parseadas, me guardaba en un array el nombre de las columnas. Y
ya para cada fila, iteraba sobre ese array para ir recogiendo en order
los resultados.

Para asegurar que funcionaba bien incluso cuando no conseguía parsear,
en el caso de no poder parsear las columnas directamente creaba un array
a partir de los atributos resultantes en la consulta. En ese caso las
columnas del resultado no aparecían en el orden introducido, pero no
está mal ya que el usuario tampoco había introducido una select conforme
a lo acordado.

Saludos,

javier ramírez

No está mal la solución. Me toca meter un poquito más de código, pero
bueno.

Muchas gracias a todos por vuestra ayuda