ruby-on-rails - many - rails references
Rails has_many association count hijo filas (4)
¿Cuál es la "manera de los rieles" para agarrar eficientemente todas las filas de una tabla de padres junto con un conteo de la cantidad de hijos que tiene cada fila?
No quiero usar counter_cache
ya que quiero ejecutar estos conteos en función de algunas condiciones de tiempo.
El ejemplo del blog cliché: Tabla de artículos. Cada artículo tiene 0 o más comentarios.
Quiero poder saber cuántos comentarios tiene cada artículo en la última hora, día, semana.
Sin embargo, lo ideal es que no quiera iterar sobre la lista y hacer llamadas SQL separadas para cada artículo, ni tampoco quiero usar :include
para obtener previamente todos los datos y procesarlos en el servidor de aplicaciones.
Quiero ejecutar una declaración SQL y obtener un conjunto de resultados con toda la información.
Sé que puedo codificar el SQL completo, y tal vez podría usar un .find
y simplemente establecer los parámetros :joins
.find
:group
y :conditions
... PERO me pregunto si hay una forma "mejor" ... también conocido como "el camino de los rieles"
Gracias por adelantado
Versión Rails 3
Para Rails 3, estarías viendo algo como esto:
Article.select( "articles.*, count(comments.id) AS comments_count" )
.joins( "LEFT OUTER JOIN comments ON comments.article_id = articles.id" )
.group( "articles.id" )
Gracias a por la versión de Rails 2.
Desde una perspectiva de SQL, esto parece trivial: simplemente escriba una nueva consulta.
Desde la perspectiva de Rails, los valores que usted menciona son valores computados. Por lo tanto, si usa find_by_sql
, la clase Modelo no conocerá los campos computados y, por lo tanto, devolverá los valores computados como cadenas incluso si logra traducir la consulta al lenguaje Rails. Vea la pregunta vinculada a continuación.
La deriva general (de las respuestas que obtuve a esa pregunta) fue que una clase separada fuera responsable de la acumulación / cálculo de los valores deseados.
Esta llamada de activerecord debe hacer lo que quieras:
Article.find(:all, :select => ''articles.*, count(posts.id) as post_count'',
:joins => ''left outer join posts on posts.article_id = articles.id'',
:group => ''articles.id''
)
Esto devolverá una lista de objetos de artículo, cada uno de los cuales tiene el método post_count
que contiene el número de publicaciones en el artículo como una cadena.
El método ejecuta sql similar al siguiente:
SELECT articles.*, count(posts.id) AS post_count
FROM `articles`
LEFT OUTER JOIN posts ON posts.article_id = articles.id
GROUP BY articles.id
Si tiene curiosidad, esta es una muestra de los resultados de MySQL que puede ver al ejecutar dicha consulta:
+----+----------------+------------+
| id | text | post_count |
+----+----------------+------------+
| 1 | TEXT TEXT TEXT | 1 |
| 2 | TEXT TEXT TEXT | 3 |
| 3 | TEXT TEXT TEXT | 0 |
+----+----------------+------------+
Una forma simple que solía resolver este problema era
En mi modelo lo hice:
class Article < ActiveRecord::Base
has_many :posts
def count_posts
Post.where(:article_id => self.id).count
end
end
Ahora, puedes usar por ejemplo:
Articles.first.count_posts
No estoy seguro de si puede ser más eficiente, pero es una solución y, en mi opinión, más elegante que las otras.