简体   繁体   中英

Why is my rails nested simple form rendering so slow?

Using Rails 4.2 with the following relevant gems: 'jquery-turbolinks' 'turbolinks', '~> 2.4.0' 'simple_form', '~> 3.0.2' "select2-rails", '3.5.9.1' 'cocoon', '~> 1.2.6'

Here is my console in local run for the page/form in question (notice the issue with View being so slow):

Started GET "/cases/2936/edit_case_contacts" for ::1 at 2018-03-06 18:39:13 -0800
Processing by CasesController#edit_case_contacts as HTML
  Parameters: {"id"=>"2936"}
  User Load (1.0ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1  ORDER BY "users"."id" ASC LIMIT 1  [["id", 90]]
  Case Load (1.2ms)  SELECT  "cases".* FROM "cases" WHERE "cases"."id" = $1 LIMIT 1  [["id", 2936]]
  Firm Load (1.0ms)  SELECT  "firms".* FROM "firms" WHERE "firms"."id" = $1 LIMIT 1  [["id", 16]]
  Contact Load (1.4ms)  SELECT "contacts"."first_name", "contacts"."last_name", "contacts"."email", "contacts"."company_name", "contacts"."id", "contacts"."type", "contacts"."prefix", "contacts"."suffix" FROM "contacts" WHERE "contacts"."firm_id" = $1  [["firm_id", 16]]
  Incident Load (1.3ms)  SELECT  "incidents".* FROM "incidents" WHERE "incidents"."case_id" = $1 LIMIT 1  [["case_id", 2936]]
  Medical Load (1.3ms)  SELECT  "medicals".* FROM "medicals" WHERE "medicals"."case_id" = $1 LIMIT 1  [["case_id", 2936]]
  Resolution Load (1.4ms)  SELECT  "resolutions".* FROM "resolutions" WHERE "resolutions"."case_id" = $1 LIMIT 1  [["case_id", 2936]]
  Rendered shared/_javascript_case_tabs.html.erb (0.6ms)
  Rendered shared/_case_tabs.html.erb (24.1ms)
  Rendered cases/_case_contact_fields.html.erb (5.0ms)
  CaseContact Load (1.3ms)  SELECT "case_contacts".* FROM "case_contacts" WHERE "case_contacts"."case_id" = $1  [["case_id", 2936]]
  Contact Load (1.9ms)  SELECT "contacts".* FROM "contacts" WHERE "contacts"."id" IN (2132, 2130, 1922, 1918, 1935, 1931, 1921, 2066, 2129, 2158, 2118)
  Rendered cases/_case_contact_fields.html.erb (6.0ms)
  Rendered cases/_case_contact_fields.html.erb (4.9ms)
  Rendered cases/_case_contact_fields.html.erb (4.9ms)
  Rendered cases/_case_contact_fields.html.erb (6.0ms)
  Rendered cases/_case_contact_fields.html.erb (5.3ms)
  Rendered cases/_case_contact_fields.html.erb (5.2ms)
  Rendered cases/_case_contact_fields.html.erb (5.4ms)
  Rendered cases/_case_contact_fields.html.erb (5.0ms)
  Rendered cases/_case_contact_fields.html.erb (5.4ms)
  Rendered cases/_case_contact_fields.html.erb (5.5ms)
  Rendered cases/_case_contact_fields.html.erb (5.3ms)
  Rendered cases/_case_contact_fields.html.erb (5.1ms)
  Rendered cases/_case_contact_fields.html.erb (6.1ms)
  Rendered cases/_case_contact_fields.html.erb (4.9ms)
  Rendered cases/_case_contact_fields.html.erb (4.8ms)
  **Rendered cases/edit_case_contacts.html.erb within layouts/application (197.9ms)**
  **Rendered layouts/_head.html.erb (311.1ms)**
  Rendered layouts/_navigation_links.html.erb (0.7ms)
  Rendered layouts/_navigation.html.erb (5.4ms)
   (1.7ms)  SELECT COUNT(*) FROM "notifications" WHERE (user_id = 90 and is_read = 'f')
  Case Load (2.5ms)  SELECT "cases".* FROM "cases" WHERE "cases"."firm_id" = $1  [["firm_id", 16]]
  Rendered time_entries/_form.html.erb (30.6ms)
  Rendered layouts/_side_navigation_javascript.html.erb (36.9ms)
  Rendered layouts/_side_navigation.html.erb (49.9ms)
  Rendered layouts/_messages.html.erb (0.5ms)
  Rendered layouts/_javascript_application.html.erb (0.5ms)
Completed 200 OK in 618ms (Views: 586.0ms | ActiveRecord: 16.0ms)
source=rack-timeout id=b6ee1bed757a24fb10c794c3e80d80ed timeout=15000ms service=646ms state=completed
source=rack-timeout id=f0cc00f68250d81864e108b8690fa9d4 timeout=15000ms state=ready
source=rack-timeout id=f0cc00f68250d81864e108b8690fa9d4 timeout=15000ms service=0ms state=active

Here is my form that renders the cocoon partial:

<%= simple_form_for @case do |f| %>
  <div class="case-header">
    <div class="case-title">
      <div style="font-size: 24px;">
        <strong><%= @case.name %></strong><br>
      </div>
      <div id="case-buttons">
        <ul>
          <li><%= link_to 'Cancel', show_case_contacts_path(@case), :class => 'dark' %></li>
          <li><%= f.submit :class => 'sub2-small dark-right', :value => 'Save' %></li>
        </ul>
      </div>
    </div>
    <strong>Case #: </strong><%= @case.case_number %>

    <div class="container-fluid" style="padding: 0;">
      <div class="row">
        <div class="col-md-12">
          <%= render 'shared/case_tabs' %>
        </div>
      </div>
    </div>
  </div>

  <div class="case_contacts-edit-container">
    <%= link_to_add_association 'ADD CONTACT', f, :case_contacts, :"data-association-insertion-node" => "#header_row", :"data-association-insertion-method" => "after", class: 'action-button insure pull-right' %>
     <table id="info-table3">
      <tbody id="case_contacts_">
      <tr id="header_row">
        <td class="gray-back">
          <strong>Name</strong>
        </td>
        <td class="gray-back">
          <strong>Case Role</strong>
        </td>
        <td class="gray-back" colspan="2">
          <strong>Note</strong>
        </td>
      </tr>
        <%= f.simple_fields_for :case_contacts, f.object.case_contacts.includes(:contact).sort_by { |a| [a.name_of_contact_for_sorting] } do |case_contact| %>
          <%= render 'case_contact_fields', :f => case_contact, cache: true %>
        <% end %>
      </tbody>
    </table>
  </div>
<% end %>

<script type="text/javascript">
  $(document).ready(function() {
      $('select').select2();
  });
</script>

Here is the content of the partial:

<tr class="nested-fields insurance-field">
    <td>
        <%= f.association :contact, :collection => @firm_contacts, :prompt => "Add Contact", :class => 'table-input', :label => false, hint: false, input_html: { id: 'contact_prompt'} %>
    </td>
    <td>
        <div id="popup_case"></div>
        <%= f.input :role, collection: Contact::ROLES, :prompt => "Choose Role", :class => 'table-input', :label => false, hint: false, input_html: { id: 'role_prompt'} %>
    </td>
    <td colspan="2">
        <%= f.text_field :note, :prompt => "Add Note", :class => 'table-input-75', :label => false, hint: false %>

        <%= f.hidden_field :firm_id, :value => @firm.id, hint: false %>

        <%= link_to_remove_association f, class: 'dark-small remove_case_contacts' do %><span id="remove" class="glyphicon glyphicon-remove pull-right" original-title="Remove Contact", hint: false ></span><% end %>
    </td>
</tr>

<script type="text/javascript">
$(document).ready(function() {

      $('#case_contacts_').on('cocoon:before-insert', function() {

      })
      .on('cocoon:after-insert', function(e, insertedItem) {
             $('#contact_prompt').select2();
             $('#role_prompt').select2();
      })
      .on("cocoon:before-remove", function() {

      })
      .on("cocoon:after-remove", function() {
        /* e.g. recalculate order of child items */
      });

});
</script>

Notice from the console log above that it renders the _head partial pretty slow as well, well here it is:

<head>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title><%= content_for?(:title) ? yield(:title) : "Litigo | Legal Software" %></title>
  <meta name="description" content="<%= content_for?(:description) ? yield(:description) : "Litigo | Legal Software" %>">
  <link href="<%= Rails.env.production? ? 'https' : 'http' %>://fonts.googleapis.com/css?family=Arimo:400,700|Changa+One" rel='stylesheet' type='text/css'>
  <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
  <%= stylesheet_link_tag 'application', "#{Rails.env.production? ? 'https' : 'http'}://fonts.googleapis.com/css?family=Arimo:400,700|Changa+One" %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
  <script type="text/javascript" src="https://js.stripe.com/v2/"></script>
  <%= csrf_meta_tags %>
  <% tag :meta, :name => "stripe-key", :content => STRIPE_PUBLIC_KEY %>
  <%= favicon_link_tag 'favicon.png' %>
</head>

I am not really sure how I can reduce the rendering timings. I don't even see any low hanging fruit... help!

Is this development or production? Because if it is development, that would explain why the _head is slower (because there are no pre-compiled assets).

Things I notice:

  • in the edit_case_contacts you call a sort_by after fetching from the database (why not let the database sort the data immediately?)
  • in the partial you have a piece of javascript which seems identical for all partials, so extract it
  • Also: better to place all your javascript sprinkles inside a separate js since then it can be precompiled in production and included in application.js as well

[EDIT: how to sort on "name of contact"]

You are now write the following:

f.object.case_contacts.includes(:contact).sort_by { |a| [a.name_of_contact_for_sorting] }

This will fetch the case-contacts including contacts, return an error, and then sort that array using sort_by . Imho it will be more efficient to let the database sort this using order . So write something like

f.object.case_contacts.includes(:contact).order("contacts.name")

assuming you have a attribute name for your contact. More options:

  • .order("contacts.last_name, contacts.first_name") to sort on multiple fields
  • .order("contacts.name asc") or .order("contacts.name desc") to choose direction

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM