2013-03-21 12 views
8

Vorrei utilizzare qualcosa come find_in_batches, ma invece di raggruppare oggetti AR completamente istanziati, vorrei raggruppare un determinato attributo, come, diciamo, l'id. Quindi, in sostanza, una miscela di usare find_in_batches e pluck:Rails: query di attributi con batch utilizzando AREL

Cars.where(:engine => "Turbo").pluck(:id).find_in_batches do |ids| 
    puts ids 
end 

# [1, 2, 3....] 
# ... 

C'è un modo per fare questo (magari con Arel) senza dover scrivere la logica/Limite di offset me stesso o ricorrente di impaginazione gemme come si impaginare o kaminari?

risposta

2

Questa non è la soluzione ideale, ma qui è un metodo che è sufficiente copiare-paste la maggior parte dei find_in_batches ma comporta un aumento rispetto al posto di un array di dischi (non testati) - solo scimmia-patch in Relation:

def in_batches(options = {}) 
    relation = self 

    unless arel.orders.blank? && arel.taken.blank? 
    ActiveRecord::Base.logger.warn("Scoped order and limit are ignored, it's forced to be batch order and batch size") 
    end 

    if (finder_options = options.except(:start, :batch_size)).present? 
    raise "You can't specify an order, it's forced to be #{batch_order}" if options[:order].present? 
    raise "You can't specify a limit, it's forced to be the batch_size" if options[:limit].present? 

    relation = apply_finder_options(finder_options) 
    end 

    start = options.delete(:start) 
    batch_size = options.delete(:batch_size) || 1000 

    relation = relation.reorder(batch_order).limit(batch_size) 
    relation = start ? relation.where(table[primary_key].gteq(start)) : relation 

    while (size = relation.size) > 0  

    yield relation 

    break if size < batch_size 

    primary_key_offset = relation.last.id 
    if primary_key_offset 
     relation = relation.where(table[primary_key].gt(primary_key_offset)) 
    else 
     raise "Primary key not included in the custom select clause" 
    end 
    end 
end 

Con questo, si dovrebbe essere in grado di fare:

Cars.where(:engine => "Turbo").in_batches do |relation| 
    relation.pluck(:id) 
end 

questa non è la migliore realizzazione possibile (soprattutto per quanto riguarda primary_key_offset calcolo, che crea un'istanza di un record), ma si ottiene lo spirito.

+0

è stato un buon tentativo, infatti. Preferirei piuttosto una soluzione non-patch-patch, dal momento che voglio applicare la suddetta logica in una libreria che può essere distribuita da diversi progetti, e mi piacerebbe essere il meno invadente possibile riguardo l'iniezione di codice in AR . – ChuckE

+0

Buon punto ... quindi rendilo un metodo di classe. Immagino che la tua lib sarà inclusa nei modelli comunque, e dovrebbe funzionare allo stesso modo finché viene usato AR. –

+0

Terminato utilizzando i metodi .limit e .offset di ARel. Sto solo dicendo che sarebbe bello avere una soluzione così pronta per Rails. – ChuckE

Problemi correlati