Find(:all) inteligente

Hola a todos,
tengo un modelo que guarda los últimos accesos de los administradores a
la parte privada /admin de una Web. El tema es que quiero mostrar en una
página un listado con las últimos accesos, por ejemplo:

1 de Abril

Usuario A se ha desconectado 10:50:22
Usuario A se ha conectado 10:35:10
Usuarui B se ha conectado 09:10:40

30 de Mayo

Usuario A se ha desconectado 16:20:12
Usuario A se ha conectado 13:35:01

28 de Mayo

Hola a todos,
tengo un modelo que guarda los últimos accesos de los administradores a
la parte privada /admin de una Web. El tema es que quiero mostrar en una
página un listado con las últimos accesos, por ejemplo:

1 de Abril

Usuario A se ha desconectado 10:50:22
Usuario A se ha conectado 10:35:10
Usuarui B se ha conectado 09:10:40

30 de Mayo

Usuario C se ha desconectado 16:20:12
Usuario C se ha conectado 13:35:01

El problema es que quiero mostrar estos logs de los últimos 5 días, pero
no de los últimos 5 días desde hoy en atrás, sino de los últimos días
que tengo logs. ¿Alguien sabe si esto se puede hacer de alguna forma
rápida?

Esto es lo que tengo ahora:

@logs = Log.find(:all, :limit => 15, :order => ‘created_at desc’)
@log_days = @logs.group_by { |l| l.created_at.beginning_of_day }

Aquí busco los últimos 15 logs, pero me gustaría cambiar y mostrar los
logs de los últimos 5 días con datos.

Gracias a todos.

Hola,

@logs = Log.find(:all, :limit => 15, :order => ‘created_at desc’)
@log_days = @logs.group_by { |l| l.created_at.beginning_of_day }

Una opción simple es hacer dos queries, pero supongo que quieres evitar
eso.

Una forma en puro sql que se me ocurría (para MySQL) es hacer una
subselect que obtenga los 5 últimos días y luego hacer un IN con la
select principal… el problema es que en mysql no te dejan poner
‘limit’ en las subselects.

Así que cambiando la subselect por una tabla dinámica, me queda esto

select * from logs, (
select date(created_at) as day_group from logs group by date(created_at)
order by day_group DESC limit 5
) as dates
where date(logs.created_at) = day_group
order by logs.created_at DESC

Y ahora eso hay que traducirlo a un find. Yo cuando tengo una query así
de bajo nivel creo un método en el modelo y hago un find_by_sql dentro
de ese método.

Como ejercicio, si prefieres usar un find de toda la vida se puede hacer

Log.find(:all,:joins=>“INNER JOIN (select date(created_at) as day_group
from logs group by date(created_at) order by created_at DESC limit 5) as
dates”,:conditions=>‘date(logs.created_at) =
dates.day_group’,:order=>‘logs.created_at DESC’)

Y con eso te debería funcionar.

Saludos,

javier ramírez

p.s. el rendimiento de usar funciones de MySQL directamente en un group
by y en una tabla dinámica no es la mejor del mundo, pero como entiendo
que esto es una tarea de administración y que se lanzará poco, no parece
un problema a priori.

Así que cambiando la subselect por una tabla dinámica, me queda esto

select * from logs, (
select date(created_at) as day_group from logs group by
date(created_at) order by day_group DESC limit 5
) as dates
where date(logs.created_at) = day_group
order by logs.created_at DESC

un apunte rápido… podrías cambiar el group by por un distinct sobre la
tabla dinámica

select distinct date(created_at) as day_group from logs order by
day_group DESC limit 5
) as dates

ahora mismo no sé qué sería más óptimo sobre la db, si agrupar o marcar
el distinct

sea como sea el resultado no debería cambiar, pero lo mismo esta segunda
forma queda un pelín más clara

saludos,

javier ramírez

Muchas gracias Javier,
haré un par de pruebas y ya daré los resultados por aquí.

Un saludo.