references rails many inverse_of has_and_belongs_to_many has foreign belong accepts_nested_attributes_for ruby-on-rails grouping has-many

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.

¿Cómo hacer que los rieles devuelvan los atributos SUM (columnName) con el tipo de datos correcto en lugar de una cadena?


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.