9

Ich habe ein aktives Panel mit einer abhängigen Auswahl, d. H. Die Wahl auf der ersten Dropdown-Auswahl wirkt sich auf das, was in der zweiten Dropdown-Liste.Rails 4 - eifrig laden auf abhängige Auswahl verursacht Fehler (Rails4/Active Admin)

Alles funktionierte vor ein paar Monaten perfekt, aber ich habe erst gestern festgestellt, dass es nicht mehr funktioniert.

Ich habe es geschafft, zu finden, was den Fehler verursacht: Wenn ich die Eager loading entfernen ("include"), dann funktioniert es wieder.

FUNKTIONIERT NICHT: (aktuelle Version):

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

ich diesen Fehler (Form Chrom Entwickler-Tools-Konsole)

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 

WORKING, wenn ich entfernen "include"/eifriges Laden:

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

Es funktioniert perfekt in diesem Fall.

Aber ich möchte wirklich gerne Subsektoren laden, so frage ich mich, was diesen Fehler verursacht, was hat sich seit seiner Arbeit geändert. Ich habe ein paar Annahmen, aber ich kann den Schuldigen nicht finden.

  • Did Rails 4 Änderung der Art und Weise finde ich verwenden sollte (params [: id] ..) oder die Art, wie ich eifrig Laden

  • hat aktiv Admin die Art und Weise behandelt sie eifrig Laden verwenden sollten: vielleicht funktioniert es nur auf Index- und nicht auf Bearbeitungsseiten ...

  • hat turbolinks jetzt auf Rails 4 den Weg geändert, den ich eifrig laden muss?

Hier ist der Code:

- Active Admin

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 

- das Formular mit den 2-abhängigen wählt

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 

- das JavaScript einschalten:

 // 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 
     }; 

hinzugefügte Datei

class DealSector < ActiveRecord::Base 
    has_many :deal_subsectors 
end 

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

Antwort

1

Schienen 4 kommt mit einigen Änderungen in Bezug auf Eager-Lade-Algorithmus. können Sie den folgenden Code-Schnipsel in Ihrem Fall versuchen:

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

oder

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

erste wird die Daten in einzelner Abfrage aber zweiten holen wird zwei Abfragen machen.

+0

scheint zu funktionieren. nur eine Frage: ist es normal, dass die Ladegeschwindigkeit, die ich in meinem Terminal sehen kann, höher ist mit @deal_subsectors = DealSector.ager_load (: deal_subsectors) .find (params [: deal_sector_id]). deal_subsectors als wenn ich KEINE eifrigen Ladevorgang mache (@deal_subsectors = DealSector.find (params [: deal_sector_id]). deal_subsectors? Da ich nicht viele Untersektoren habe (im Moment weniger als 20), ist es vielleicht normal, dass das E-Laden länger dauert als ohne E-Laden Recht zu sagen, es eifrig wird sich auszahlen, wenn ich noch viele Subsektoren haben werde? – Mathieu

+0

Ja @mathieu Ihre Gedanken sind absolut richtig Die meiste Zeit eifrig Laden halten Sie von der N + 1 Abfrage Trap, ohne eifrig laden können Sie sein 100 Abfrage ausführen, um 1 Ergebnis zu erhalten, anstatt 1 Abfrage zu laufen, um 100 Ergebnisse zu erhalten.Egis Laden wird immer auszahlen, möglicherweise können Sie eine oder zwei Ausnahmen erhalten .. In Ihrem Fall eifrigloading definitiv reduzieren Sie die Abfrage Zeit und machen yo Deine Antwort schnell. größere Nr. von Daten haben Sie mehr Nutzen, den Sie vom eifrigen Laden bekommen. – meOn

+0

Tx für Ihre weiteren Erklärungen – Mathieu

2

Wenn Sie ActiveRecord::find nennen - es bedeutet, dass Sie erwarten ein ein, einziges Modell von der DB zu bekommen. Dann beziehen Sie sich auf dieses Modell und rufen dealsubsectors - ich nehme an, es ist has_many Beziehung zu Ihrem Modell. Es wird 2 Abfragen erzeugen: zuerst, um Original zu holen DealSelector, Sekunde - alles in Verbindung stehende DealSubsectors. Es gibt nichts, was Sie optimieren können (außer Sie dealsubsectors ist eine benutzerdefinierte Methode in Ihrem Modell, nicht die Beziehung).

Wenn Sie sehen, dass etwas Ihre DB mit Abfragen trifft - müssen Sie an anderer Stelle suchen. Sagen Sie, Ihr Formular - zeigen Sie nur einen Client pro Formular an? Ist dies nicht der Fall, werden alle DealSector- und DealSubsector-Elemente für jeden neuen Client erneut iteriert und abgerufen. Versuchen Sie, mehr Code bereitzustellen.

+0

ja es hat eine has_many Beziehungen. Nun, wenn Sie sagen, es gibt nichts, was Sie optimieren können, aber ich denke nicht, dass das wahr ist: Ich dachte, egaer laden wxas genau das Laden der zugehörigen Ressourcen in einem Aufruf, so dass die Abfrage effizienter ist. also hier möchte ich mit dem Spielsektor die zugehörigen Subsektoren eifrig laden. Ich werde Code für Modellbeziehungen hinzufügen. Sag mir, welchen Code du sonst noch brauchst. – Mathieu

+0

Mit diesem Code gibt es keine Möglichkeit, eifrig laden zu können: 'DealSector.find (params [: deal_sector_id]). Deal_subsectors' - Sie können es von der Konsole' (Rails c) 'ausführen und die Abfragen sehen. Es werden 2 Abfragen ausgelöst: um 'DealSector' zu finden und 'DealSubsectors' zu holen. Sie müssen über andere Orte nachdenken, an denen Sie einige Modelle laden - z. Ihrer Meinung nach. – shlajin

+0

natürlich. Was ich mit dieser Frage erwarte, ist nicht, dass man weiß, dass es nicht so funktioniert wie es ist. ich weiß das. Was ich erwarte, ist eher, wie ich es schaffen kann, Deal-Teilsektoren zu belasten. Ich weiß in der Tat, dass Sie Modelle auf aktiven Admin mit laden können: enthält, aber ich brauche Anleitung und Antworten, um mir mit präzisen Antworten oder Ideen zu helfen. – Mathieu

0

Warum können Sie nicht einfach alle DealSubsektor-Datensätze für die angegebene sector_id abrufen?

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

Yury danke, aber ich sage nicht, was ich benutzte, funktionierte nicht. das funktioniert perfekt: @deal_subsectors = DealSector.find (params [: deal_sector_id]). deal_subsectors ABER ich möchte das eifrige Laden verwenden. – Mathieu