13

EjemploAsociación ActiveRecord seleccionar el recuento de registros incluidos

class User 
    has_many :tickets 
end 

quiero crear asociación que contiene la lógica de las entradas de conteo de usuario y utilizarlo en incluye (usuario ticket_count has_one)

Users.includes(:tickets_count) 

Probé

has_one :tickets_count, :select => "COUNT(*) as tickets_count,tickets.user_id " ,:class_name => 'Ticket', :group => "tickets.user_id", :readonly => true 

User.includes(:tickets_count) 

ArgumentError: Unknown key: group 

En este caso, la consulta de asociación en include debe usar c ount with group by ... ¿Cómo puedo implementar esto usando rieles?

actualización

  • No puedo cambiar la estructura de tablas
  • quiero generar AR 1 consulta para la recogida de los usuarios incluye

Update2

que sé SQL y sé cómo seleccionar esto con join, pero mi pregunta ahora es como "Cómo obtener datos". Mi pregunta es sobre la construcción de asociación que puedo usar en incluye. Gracias

Update3 Intenté crear asociación creada como ticket_count has_one usuario, pero

  1. parece has_one no soporta las extensiones de asociación
  2. has_one no soporta: opción del grupo
  3. has_one no es compatible con finder_sql

Respuesta

12

Prueba esto:

class User 

    has_one :tickets_count, :class_name => 'Ticket', 
    :select => "user_id, tickets_count", 
    :finder_sql => ' 
     SELECT b.user_id, COUNT(*) tickets_count 
     FROM tickets b 
     WHERE b.user_id = #{id} 
     GROUP BY b.user_id 
    ' 
end 

Editar:

Parece que la asociación has_one no soporta la opción finder_sql.

Se puede lograr fácilmente lo que desea mediante el uso de una combinación de scope/class métodos

class User < ActiveRecord::Base 

    def self.include_ticket_counts 
    joins(
    %{ 
     LEFT OUTER JOIN (
     SELECT b.user_id, COUNT(*) tickets_count 
     FROM tickets b 
     GROUP BY b.user_id 
     ) a ON a.user_id = users.id 
    } 
    ).select("users.*, COALESCE(a.tickets_count, 0) AS tickets_count") 
    end  
end 

Ahora

User.include_ticket_counts.where(:id => [1,2,3]).each do |user| 
    p user.tickets_count 
end 

Esta solución tiene implicaciones en el rendimiento si usted tiene millones de filas en la tabla tickets . Debería considerar filtrar el conjunto de resultados JOIN proporcionando WHERE a la consulta interna.

+0

carriles 3.2 me da ArgumentError: Clave desconocida: sql – Fivell

+0

has_one tiene las siguientes opciones [: class_name,: foreign_key,: select,: conditions,: include,: extender,: readonly,: validate,: remote,: dependent,: counter_cache, : primary_key,: inverse_of,: order,: as,: autosave] – Fivell

+0

@Fivell, actualizó la respuesta. Se suponía que debía usar 'finder_sql' en lugar de' sql'. He actualizado mi respuesta, eche un vistazo. –

8

Puede simplemente usar para un usuario en particular:

user.tickets.count 

O si desea que este valor sea almacenado en caché automáticamente por Rails.

declarar una counter_cache => true en el otro lado de la asociación

class ticket 
    belongs_to :user, :counter_cache => true 
end 

También es necesario una columna en la tabla de usuario que tickets_count llamado. Con esto cada vez que agrega un nuevo ticket a un usuario, los rieles actualizarán esta columna, de modo que cuando ingrese su registro de usuario, simplemente puede utilizar esta columna para obtener el número de tickets sin consulta adicional.

+0

actualicé mi pregunta, no puedo cambiar la estructura de la tabla – Fivell

+0

Si no puede cambiar la estructura de la tabla, solo necesita agregar un método virtual que devuelve el recuento en su modelo 'Usuario':' def tickets_count; @tickets_count || = tickets.count; end' y luego puede llamarlo como un atributo normal '@ user.tickets_count' – edgarjs

6

No es bonita, pero funciona:

users = User.joins("LEFT JOIN tickets ON users.id = tickets.user_id").select("users.*, count(tickets.id) as ticket_count").group("users.id") 
users.first.ticket_count 
+0

Tanques de respuesta ... pero no funciona ... ¿y si el usuario no tiene tickets? y cómo agrupa el número de tickets por usuario? Lo intentaste ? También quiero utilizar incluye – Fivell

+0

Sí, lo probé y funciona bien para mí. ¿Por qué quieres usar includes? – Thilo

+0

1) se une utiliza combinación interna, se necesita combinación 2) ¿dónde se encuentra la declaración group by user.id en nuestro ejemplo? (Necesario para contar) – Fivell

0

¿Qué pasa con la adición de un método en el modelo de usuario que realiza la consulta?

No modificaría la estructura de la tabla, o tampoco puede modificarla?

+1

¿cómo puedo llamar este método de forma dinámica con "includes"? – Fivell

Cuestiones relacionadas