No, no se trata de una dieta milagrosa. Se trata de una situación en la que me he encontrado más de una vez y que nunca resuelvo de la misma forma. Esta que he aplicado hoy me parece lo suficientemente buena como para ponerla por aquí y así no volver a darle más vueltas a esto si me toca hacerlo de nuevo.
Se trata del clásico "Archivo" que se muestra habitualmente en la columna de un blog de tal forma que muestre un enlace a todos los meses en los que existe algún contenido publicado. Algo tal que:
2010 Enero
2009 Diciembre, Octubre, Febrero
Y así sucesivamente. Los enlaces nos llevan a un listado con los contenidos que se publicaron dicho mes.
El problema es que si hay muchos contenidos hacerlo tirando del modelo en cuestión puede resultar una operación muy pesada.
Si por el contrario dejamos el trabajo duro de agrupar por año y mes al motor de BBDD la cosa se agiliza notablemente. En mi caso, detrás tengo MySQL y el siguiente helper me ha solucionado el problema:
def archive
yearandmonths = ActiveRecord::Base.connection.select_rows(<<QUERY)
SELECT DISTINCT(DATE_FORMAT(published_at, "%Y-%c"))
FROM highlights
WHERE published_at IS NOT NULL
ORDER BY published_at DESC
QUERY
yearandmonths.map do |yearandmonth|
year, month = yearandmonth.first.split('-')
Struct.new(:year, :month).new(year, month.to_i)
end
end
La tabla asociada a los contenidos que pretendo mostrar es "highlights" y el campo con la fecha de publicación "published_at". No costaría mucho que la función recibiese esto parametrizado pero en este caso sólo necesito el helper en esta parte de la aplicación.
Aquí asumo que cualquier contenido que tiene fecha de publicación ("published_at") está publicado (es decir, que no existe otro campo que determine si puede verse dicho contenido). Idealmente, para que la consulta fuese lo más rápida posible debería existir un índice en dicho campo.
Después, en la vista, uso el helper llevando su salida al "group_by" quedando la cosa tal que así:
<% archive.group_by(&:year).each do |year, year_months| %>
<strong><%= year %></strong>
<% year_months.each do |m| %>
<%= link_to t('date.month_names')[m.month],
highlights_path(:year => year, :month => m.month) %>
<% end %>
Y eso es todo. Un posete, que ya iba tocando para que no se me quede el mes de febrero fuera del "archivo". :)
