9

Ho un pannello attivo con una selezione dipendente, vale a dire la scelta sul primo menu a discesa impatta ciò che appare nel secondo menu a discesa.Rails 4 - caricamento ingombrante su selezione dipendente che causa errore (Rails4/Active Admin)

Tutto funzionava perfettamente bene qualche mese fa ma ho appena realizzato ieri che non funziona più.

Sono riuscito a trovare la causa dell'errore: se rimuovo il caricamento di eager ("include"), quindi funziona di nuovo.

NON LAVORO: (versione attuale):

@deal_subsectors = DealSector.find(params[:deal_sector_id], 
    include: :deal_subsectors).dealsubsectors 

ottengo questo errore (console strumenti forma cromo dev)

GET http://localhost:3000/admin/deals/deal_subsectors_by_deal_sector?deal_sector_id=2 404 (Not Found)  
send @ jquery.js?body=1:9660  
jQuery.extend.ajax @ jquery.js?body=1:9211  
jQuery.(anonymous function) @ jquery.js?body=1:9357  
jQuery.extend.getJSON @ jquery.js?body=1:9340  
update_deal_subsector @ active_admin.js?body=1:19  
(anonymous function) @ active_admin.js?body=1:12  
jQuery.event.dispatch @ jquery.js?body=1:4666  
elemData.handle @ jquery.js?body=1:4334  
ListPicker._handleMouseUp @ about:blank:632 

LAVORO, quando rimuovo "include"/carico desideroso:

@deal_subsectors = DealSector.find(params[:deal_sector_id]).deal_subsectors 

Funziona perfettamente in quel caso.

Ma voglio davvero caricare i sottosettori delle transazioni, quindi mi chiedo che cosa stia causando questo errore, cosa è cambiato da quando funzionava. Ho alcune supposizioni ma non riesco a trovare il colpevole.

  • Forse Rails 4 cambiamento del modo in cui dovrei usare find (params [: id] ..), o il modo in cui dovrei usare eager loading

  • ha cambiato Admin attiva il modo in cui gestisce eager loading: forse funziona solo su indice e non su pagine di modifica ...

  • ha fatto i turbolinks ora su Rails 4 cambiare il modo in cui devo caricare carico?

Ecco il codice:

- su Admin attivo

ActiveAdmin.register Deal do 

# controller for the multi-select sector/subsector in the form 
# does 2 things at same time: creates method and automatically defines the route of the method defined in controller 
    if params[:deal_sector_id] # pass the id 
     @deal_subsectors = DealSector.find(params[:deal_sector_id], include: :deal_subsectors).dealsubsectors 
    else 
     @deal_subsectors = [] 
    end 

    render json: @deal_subsectors 
    end 

end 

- il modulo con le 2 seleziona dipendenti

form do |f| 

f.inputs "Client" do 


     f.input :deal_sector_id, 
     :label  => "Select industry:", 
     :as   => :select, 
     :prompt  => true, 
     :collection => DealSector.order("name").all.to_a 
     f.input :deal_subsector_id, 
     :label  => "Select subindustry:", 
     :as   => :select, 
     :prompt  => true, 
     :collection => DealSubsector.order("name").all.to_a   
    end 

end 

- il javascript alimentandolo:

 // for edit page 
     var deal_subsector = { }; 

     $(document).ready(function() { 
     $('#deal_deal_sector_id').change(function() { 
      update_deal_subsector(); 
     }); 
     }); 

     function update_deal_subsector() { 
      deal_sector_id = $('#deal_deal_sector_id').val(); //get the value of sector id 
      url = '/admin/deals/deal_subsectors_by_deal_sector?deal_sector_id=' + deal_sector_id; //make a query to the url passing the deal sector id as a parameter 
      $.getJSON(url, function(deal_subsectors) { 
       console.log(deal_subsectors); 
        $('#deal_deal_subsector_id').html("") //just blanks the id, blank it before populating it again if sector changes 
       for(i = 0; i < deal_subsectors.length; i++) { 
       console.log(deal_subsectors[i]); 
       $('#deal_deal_subsector_id').append("<option value=" + deal_subsectors[i].id + ">" + deal_subsectors[i].name + "</option>") 
     }; 
    }); //pass the url and function to get subsector ids and all we get is assigned to the variable subsector_id 
    }; 

      // for index page (filters) 
      $(document).ready(function() { 
       $('#q_deal_sector_id').change(function() { 
       update_deal_subsector_filter(); 
       }); 
       }); 

      function update_deal_subsector_filter() { 
       deal_sector_id = $('#q_deal_sector_id').val(); //get the value of sector id 
       url = '/admin/deals/deal_subsectors_by_deal_sector?deal_sector_id=' + deal_sector_id; //make a query to the url passing the deal sector id as a parameter 
       $.getJSON(url, function(deal_subsectors) { 
         console.log(deal_subsectors); 
       $('#q_deal_subsector_id').html("") //just blanks the id, blank it before populating it again if sector changes 
       for(i = 0; i < deal_subsectors.length; i++) { 
        console.log(deal_subsectors[i]); 
        $('#q_deal_subsector_id').append("<option value=" + deal_subsectors[i].id + ">" + deal_subsectors[i].name + "</option>") 
     }; 
    }); //pass the url and function to get subsector ids and all we get is assigned to the variable subsector_id 
     }; 

file aggiunto

class DealSector < ActiveRecord::Base 
    has_many :deal_subsectors 
end 

class DealSubsector < ActiveRecord::Base  
    belongs_to :deal_sector, :foreign_key => 'deal_sector_id' 
end 

risposta

1

Rails 4 viene fornito con alcune modifiche rispetto all'algoritmo di carico desideroso. si possono provare i frammenti di codice qui sotto nel vostro caso:

@deal_subsectors = DealSector.eager_load(:deal_subsectors).find(params[:deal_sector_id]).dealsubsectors 

o

@deal_subsectors = DealSector.includes(:deal_subsectors).find(params[:deal_sector_id]).dealsubsectors 

primo sarà recuperare i dati in singola query, ma secondo farà due query.

+0

sembra funzionare. solo una domanda: è normale che la velocità di caricamento che posso vedere nel mio terminale sia più alta con @deal_subsectors = DealSector.eager_load (: deal_subsectors) .find (params [: deal_sector_id]). deal_subsectors di quando non faccio MAI carico (@deal_subsectors = DealSector.find (params [: deal_sector_id]). deal_subsectors? Dato che non ho molti sottosettori (come meno di 20 al momento), forse è normale che il carico di lavoro richiede più tempo che senza carico eccessivo. giusto dire che il carico di lavoro pagherà quando avrò molti altri sottosettori? – Mathieu

+0

Sì @mathieu i tuoi pensieri sono assolutamente corretti. Il più delle volte il caricamento impaziente ti tiene lontano dalla trappola di query N + 1, senza il carico impaziente potresti essere eseguendo 100 query per ottenere 1 risultato invece di eseguire 1 query per ottenere 100 risultati. Il caricamento ansioso ripagherà sempre, potrebbe essere possibile ottenere una o due eccezioni. Nel tuo caso, il caricamento rapido ridurrà definitivamente il tempo di interrogazione e renderà la tua risposta veloce. più grande no dei dati avrai più benefici che ottieni dal caricamento avido. – meOn

+0

tx per ulteriori chiarimenti – Mathieu

2

Quando si chiama ActiveRecord::find - vuol dire che si aspettano di ottenere un uno, unico modello dal DB. Quindi, ti riferisci a questo modello e chiama dealsubsectors - Presumo che sia la relazione has_many al tuo modello. Produrrà 2 query: prima di recuperare originale DealSelector, seconda - tutte relative DealSubsectors. Non c'è nulla che tu possa ottimizzare (a meno che tu non sia il dealsubsectors un metodo personalizzato nel tuo modello, non la relazione).

Se vedi che qualcosa colpisce il tuo DB con delle query, devi cercare in un altro posto. Dì, il tuo modulo - mostri solo un cliente per modulo? In caso contrario, itererà e recupererà nuovamente DealSector e DealSubsector per ogni nuovo client. Prova a fornire più codice.

+0

sì, ha una relazione has_many. Beh, quando dici che non è possibile ottimizzare nulla, ma non penso sia vero: pensavo che il caricamento di wxas non fosse esattamente inteso a caricare le risorse associate in una chiamata in modo che la query fosse più efficiente. quindi qui voglio caricare con interesse i settori di gioco associati ai sottosettori. Aggiungerò del codice sui rapporti di modello. Dimmi quale altro codice avresti bisogno. – Mathieu

+0

Usando questo codice non è possibile usare il carico bisognoso: 'DealSector.find (params [: deal_sector_id]). Deal_subsectors' - puoi eseguirlo dalla console' (rails c) 'e vedere le query. Avvia 2 query: per trovare 'DealSector' e recuperare' DealSubsectors'. Devi pensare ad altri posti in cui carichi alcuni modelli, ad es. dal tuo punto di vista – shlajin

+0

ovviamente. quello che mi aspetto con questa domanda non è che sia detto che non funziona così com'è. lo so. Quello che mi aspetto è piuttosto come posso riuscire a caricare i sottosettori dell'affare. So per certo che puoi scaricare i modelli su admin attivo con: include, ma ho bisogno di guida e risposte per aiutarmi a farlo con risposte precise o idee. – Mathieu

0

Perché non è possibile recuperare tutti i record DealSubsector per il dato sector_id?

DealSubsector.where(deal_sector_id: params[:deal_sector_id]) 
+0

Grazie mille ma non sto dicendo che quello che stavo usando non funzionava. questo funziona perfettamente: @deal_subsectors = DealSector.find (params [: deal_sector_id]). deal_subsectors MA voglio usare il caricamento di eager. – Mathieu